library(lme4)

library(knitr)
library(survival)
library(coxme)


library(zoo)

library(ggthemes)
library(grid)
library(gridExtra)
library(ggbeeswarm)

library(stringr)

library(tidyverse)

library(parallel)
#Convenience functions 
numextract <- function(string){
  as.numeric(str_extract(string, "\\-*\\d+\\.*\\d*"))
}

comma <- function(x) format(x, digits = 3, big.mark = ",")

comma_1 <- function(x) format(x, digits = 1, big.mark = ",")

comma_2 <- function(x) format(x, digits = 2, big.mark = ",")

comma_p <- function(x){
  if (x < 0.001){
    return("< 0.001")
  }
  if (x<0.01 & x>=0.001){
    paste("=", format(x, digits = 3, big.mark = ","))
  }
  else{
    paste("=", format(x, digits = 2, big.mark = ","))
  }
} 

Mixed-effects Cox Model Fitting

to_model <- read.csv("clean_time_series_revise2006_2015.csv")

#for table S4
tx_hr <- haven::read_sas("SAF 2018 Q3/tx_hr.sas7bdat", NULL) %>%  
  haven::zap_formats() %>% haven::zap_labels()

to_model
#three-status, donor quality, and transplant year
three_status <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b) 
+ tx_risky_don + era_tx"

#six-status, donor quality and transplant year
six_status <- "Surv(t_1, t_2, dead) ~ tx*(status_2 + status_3 + status_4 + status_6) + 
tx_risky_don + era_tx"
formulas <- c(three_status,six_status)

fe_models <- vector(mode = "list", length(formulas))
hz_list <- vector(mode = "list", length(formulas))

for (i in seq_along(formulas)) {
  coxph_fe <- coxph(as.formula(formulas[[i]]), to_model)
  print(formulas[[i]])
  print(coxph_fe)
  fe_models[[i]] <- coxph_fe

  #estimate baseline hazard function when all covariates equal to zero 
  # Status 1A, after "Status 1A", low risk donor
  basehz <- basehaz(coxph_fe, centered=FALSE) %>% 
    mutate(hz_t = if_else(time ==1, hazard, (hazard - lag(hazard))/(time -lag(time))), 
           hz_t_time = if_else(time ==1, hz_t*time, hz_t*(time -lag(time))), 
           cum_hz = cumsum(hz_t_time)) %>% select(time, hz_t)

  hz_list[[i]] <- basehz
}
me_models <-  vector(mode = "list", length(formulas))

for (i in seq_along(formulas)) {
  f_coxme <- as.formula(paste(formulas[[i]], " + (1+ tx|center)"))
  start_time <- Sys.time()
  three_status <- coxme(f_coxme, data = to_model)
  me_models[[i]] <- three_status 
  end_time <- Sys.time()
  diff_time <- end_time - start_time
  print(f_coxme)
  print(diff_time)
}


#save.image("model_fit.RData")

Variance in transplant benefit

Here we write a function to calculate the between center combination in the survival benefit of transplant on the log hazard scale

\(survivalBenefit_i = \nu_{1i} - \nu_{0i}\)

\(Var(\nu_{i1} - \nu_{i0}) = Var(v_{1i}) + Var(\nu_{0i}) - 2*Cov(v_{1i}, v_{0i})\)

and finally since coxme returns the correlation between the random effects

\(Cov(v_{1i}, v_{0i}) = Corr(v_{1i}, v_{0i})*\sigma_{v_{0i}}\sigma_{v_{1i}}\)

variance_survival_benefit <- function(me_cox){
  variance_est <- me_cox$vcoef[[1]]
  
  var_wait <- variance_est[[1,1]]
  var_tx <- variance_est[[2,2]]
  cov_tx_wait <- variance_est[[1,2]]*sqrt(variance_est[[1,1]])*sqrt(variance_est[[2,2]])
  
  return(var_wait + var_tx - 2*cov_tx_wait)
}

3 status coxme results

three_status <- me_models[[1]]

basehz <- hz_list[[1]]

three_status_var <- variance_survival_benefit(three_status)

three_status
Cox mixed-effects model fit by maximum likelihood
  Data: to_model
  events, n = 11058, 163240
  Iterations= 30 184 
                  NULL Integrated  Fitted
Log-likelihood -107600  -105890.7 -105702

                    Chisq     df p     AIC     BIC
Integrated loglik 3418.65  10.00 0 3398.65 3325.54
 Penalized loglik 3795.97 122.76 0 3550.45 2652.96

Model:  f_coxme 
Fixed coefficients
                    coef exp(coef)   se(coef)      z     p
tx           -1.95316608 0.1418243 0.04469987 -43.70 0.000
stat_2       -1.35517243 0.2579028 0.03648152 -37.15 0.000
stat_1b      -0.94242273 0.3896826 0.03167335 -29.75 0.000
tx_risky_don  0.26049398 1.2975709 0.02801652   9.30 0.000
era_tx       -0.05394094 0.9474881 0.03047029  -1.77 0.077
tx:stat_2     1.32075844 3.7462616 0.06369779  20.73 0.000
tx:stat_1b    0.90417441 2.4698920 0.04370071  20.69 0.000

Random effects
 Group  Variable  Std Dev     Variance    Corr       
 center Intercept  0.22364632  0.05001768 -0.50908712
        tx         0.23822093  0.05674921            

The calculated variance in the survival benefit of transplant \(B = Tx - Wait\) is 0.161 on log hazard ratio scale for the 3-status model

6 status coxme results

six_status <- me_models[[2]]

basehz_six_stat <- hz_list[[2]]

six_status_var <- variance_survival_benefit(six_status)


six_status
Cox mixed-effects model fit by maximum likelihood
  Data: to_model
  events, n = 11058, 163240
  Iterations= 23 211 
                  NULL Integrated    Fitted
Log-likelihood -107600  -105838.3 -105664.7

                    Chisq     df p     AIC     BIC
Integrated loglik 3523.39  14.00 0 3495.39 3393.04
 Penalized loglik 3870.57 124.95 0 3620.67 2707.17

Model:  f_coxme 
Fixed coefficients
                    coef  exp(coef)   se(coef)      z       p
tx           -2.92406175 0.05371507 0.13932787 -20.99 0.0e+00
status_2     -0.86879490 0.41945673 0.08926304  -9.73 0.0e+00
status_3     -1.52574756 0.21745843 0.08341592 -18.29 0.0e+00
status_4     -2.16907702 0.11428305 0.07852884 -27.62 0.0e+00
status_6     -2.61411255 0.07323275 0.08224010 -31.79 0.0e+00
tx_risky_don  0.26222497 1.29981894 0.02800619   9.36 0.0e+00
era_tx       -0.05269387 0.94867038 0.03042904  -1.73 8.3e-02
tx:status_2   0.73718240 2.09003832 0.15245228   4.84 1.3e-06
tx:status_3   1.24972334 3.48937744 0.14226535   8.78 0.0e+00
tx:status_4   1.85129304 6.36804832 0.13835133  13.38 0.0e+00
tx:status_6   2.28656875 9.84111238 0.14941169  15.30 0.0e+00

Random effects
 Group  Variable  Std Dev     Variance    Corr       
 center Intercept  0.19542629  0.03819143 -0.38557673
        tx         0.21220860  0.04503249            

The calculated variance in the survival benefit of transplant \(B = Tx - Wait\) in the six-status model decreased by a factor of 0.28 from 0.161 to 0.115 on log hazard ratio scale compared to the three-status system.

Survival Benefit Calculations

hr_tx_ij <- function(model = three_status, df= to_model, i, j){
  #this function returns the log hazard ratio of transplant 
  #for patient j transplanted at center i for a given coxme model  
  fixed_effects <- fixef(model)
  x_vars <- names(fixed_effects)
  ref <- data.frame(ranef(model)[[1]])
  ref$center <- row.names(ref)
  tx_ref <- filter(ref, center == i)$tx
  
  is_int <- function(x) grepl("tx:", x)
  ints <- x_vars[sapply(x_vars, is_int)]
  non_ints <- setdiff(x_vars, ints)

  d_ij <- df %>% filter(PX_ID == j) %>% group_by(tx) %>% 
    filter(row_number()==1 & tx ==1) %>% select(one_of(non_ints))

  h_ij <- tx_ref + unname(fixed_effects['tx'])
  for (x in ints) {
      fe_tx <- unname(fixed_effects[x])
      c_list <- strsplit(x, ":")
      int_var <- c_list[[1]][2]
      h_ij <- h_ij + d_ij[[int_var]]*fe_tx
  }
  return(h_ij)
}

Function to plot survival functions under transplant or no transplant

Warnings:

  • factor variables are NOT supported, every covariate MUST be a continuous or zero/one.
  • Do not use any candidate covariates with tx in the name this will cause this function to silently fail.
  • Donor covariates should be coded with a tx_ prefix
b_ij <- function(df, base_hz, model, i, j){


fixed_effects <- fixef(model)
x_vars <- names(fixed_effects)
ref <- data.frame(ranef(model)[[1]])
ref$center <- row.names(ref)

d_ij <- df %>% filter(PX_ID == j) %>% 
  select(PX_ID, t_1, t_2, dead, one_of(x_vars)) %>% 
  mutate(time = t_1, 
         time  = ifelse(time==0, 1, time), 
         fe_lp = 0, lp_no_tx = 0)

for (x in x_vars) {
    fe_x <- unname(fixed_effects[x])

    if(grepl("tx:", x) == FALSE){
        d_ij$c_x <- d_ij[[x]]
    }
    ##add code to deal with interaction terms here
    if(grepl("tx:", x) == TRUE){
      c_list <- strsplit(x, ":")
      int_var <- c_list[[1]][2]
      d_ij$c_x <- d_ij[[int_var]]*d_ij[["tx"]]
    }

    d_ij <- d_ij %>% mutate(fe_lp = fe_lp + c_x*fe_x) %>% select(-c_x)
}

###Hypothetical when patient has always been transplanted
non_tx_terms <- lapply(x_vars, function(x) if(grepl("tx", x) == FALSE) x)
non_tx_terms <- non_tx_terms[-which(sapply(non_tx_terms, is.null))]

for (x in non_tx_terms) {
    fe_x <- unname(fixed_effects[x])
    d_ij$c_x <- d_ij[[x]]
    d_ij <- d_ij %>% mutate(lp_no_tx = lp_no_tx + c_x*fe_x) %>% select(-c_x)
}


d_ij <- left_join(base_hz, d_ij, by = c("time")) %>% 
  select(-t_1, -t_2)

d_ij <- d_ij %>% 
  mutate_all(funs(na.locf(., na.rm = FALSE)))

ctr_i_b0 <- ref[ref$center == i,]$Intercept
ctr_i_b1 <- ref[ref$center == i,]$tx

d_ij <- d_ij %>% mutate(
    fe_wait = lp_no_tx,
    fe_tx = fe_lp,
    ctr_hz_wait = hz_t*exp(fe_wait + ctr_i_b0),
    ctr_hz_tx = hz_t*exp(fe_tx + ctr_i_b0 + ctr_i_b1)
    ) %>%
    mutate(wait_surv = cumprod(1-ctr_hz_wait)) %>% 
    group_by(tx) %>% 
    mutate(
        surv_post_tx = if_else( tx ==1, cumprod(1-ctr_hz_tx), NULL), 
        surv_post_tx = max(wait_surv)*surv_post_tx) %>% ungroup()

tx_point <- d_ij %>% 
  group_by(tx) %>% 
  filter(row_number()==1 & tx==1) %>% 
  ungroup()


if (nrow(tx_point)==0) warning(paste0("Candidate ", j, " not transplanted"))

if (nrow(tx_point)>0) {
plot_i_j <- ggplot() + 
  geom_step(data = d_ij, 
            aes(y =wait_surv, 
                x = time, 
                color = "Waitlist Survival"), 
            size = 1.5) +
  geom_step(data = d_ij, 
            aes(y =surv_post_tx, 
                x = time, 
                color = "Post-transplant survival"), 
            size = 1.5) + 
  geom_ribbon(data = d_ij, 
              aes(x= time, 
                  ymin = wait_surv, 
                  ymax = surv_post_tx, 
                  fill = "Survival Benefit"), 
              alpha = 0.5) + 
  geom_point(data = tx_point, 
             aes(x = time, 
                 y = surv_post_tx, 
                 shape= "Transplant"), 
             size = 5, colour = "darkgreen") + 
  labs(x = "Time(days)", y = "Survival", shape = "", fill = "") + 
  scale_y_continuous(limits = c(0,1), breaks = seq(0,1, 0.25)) + 
  scale_x_continuous(breaks = seq(0, 3650, 365)) + 
  scale_color_manual(name = NULL, values=c("blue", "red")) + 
  scale_fill_manual(name = "", values = c("lightblue"))
    
return(plot_i_j)    
}


}

Function to calculate 5-year survival benefit

this function calculates the survival benefit for a given set of times (default is five-years). Calculates the survival function conditional upon reaching transplant (“resets” the survival curve to 100% at transplant)

Warnings:

  • factor variables are NOT supported, every covariate MUST be a continuous or zero/one.
  • Do not use any candidate covariates with tx in the name this will cause this function to silently fail.
  • Donor covariates should be coded with a tx_ prefix
ben_wait_tx <- function(df = to_model, 
                        base_hz = basehz, 
                        model = three_status, i, j, end_times = 1825){




max_end_time <- max(end_times)

fixed_effects <- fixef(model)
x_vars <- names(fixed_effects)
ref <- data.frame(ranef(model)[[1]])
ref$center <- row.names(ref)

d_ij <- df %>% 
  filter(PX_ID == j) %>% 
  select(PX_ID, t_1, t_2, dead, one_of(x_vars)) %>% 
  mutate(time = t_1, 
         time  = ifelse(time==0, 1, time), 
         fe_lp = 0, 
         lp_no_tx = 0)

for (x in x_vars) {
    fe_x <- unname(fixed_effects[x])

    if(grepl("tx:", x) == FALSE){
        d_ij$c_x <- d_ij[[x]]
    }
    ##add code to deal with interaction terms here
    if(grepl("tx:", x) == TRUE){
      c_list <- strsplit(x, ":")
      int_var <- c_list[[1]][2]
      d_ij$c_x <- d_ij[[int_var]]*d_ij[["tx"]]
    }

    d_ij <- d_ij %>% mutate(fe_lp = fe_lp + c_x*fe_x) %>% select(-c_x)
}

###Hypothetical when patient has always been transplanted
non_tx_terms <- lapply(x_vars, function(x) if(grepl("tx", x) == FALSE) x)
non_tx_terms <- non_tx_terms[-which(sapply(non_tx_terms, is.null))]

for (x in non_tx_terms) {
    fe_x <- unname(fixed_effects[x])
    d_ij$c_x <- d_ij[[x]]
    d_ij <- d_ij %>% mutate(lp_no_tx = lp_no_tx + c_x*fe_x) %>% select(-c_x)
}


d_ij <- left_join(base_hz, d_ij, by = c("time")) %>% select(-t_1, -t_2)

d_ij <- d_ij %>% 
  mutate_all(funs(na.locf(., na.rm = FALSE))) %>% 
  filter(tx ==1) %>% 
  mutate(time = time - min(time)+1)

ctr_i_b0 <- ref[ref$center == i,]$Intercept
ctr_i_b1 <- ref[ref$center == i,]$tx

d_ij <- d_ij %>% mutate(
    fe_wait = lp_no_tx,
    fe_tx = fe_lp,
    ctr_hz_wait = hz_t*exp(fe_wait + ctr_i_b0),
    ctr_hz_tx = hz_t*exp(fe_tx + ctr_i_b0 + ctr_i_b1)
    ) %>%
    mutate(wait_surv = cumprod(1-ctr_hz_wait)) %>% 
    group_by(tx) %>% 
    mutate(
        surv_post_tx = if_else( tx ==1, cumprod(1-ctr_hz_tx), NULL), 
        surv_post_tx = max(wait_surv)*surv_post_tx) %>% ungroup()


d_ij <- d_ij %>% 
  filter(time <= max_end_time) %>% 
  mutate(surv_benefit = surv_post_tx - wait_surv)

if (nrow(d_ij)==0) warning(paste0("Candidate ", j, " not transplanted"))


  s_benefit <- vector(mode = "numeric", length = 2)
  
  wait_5 <- filter(d_ij, time == end_times)$wait_surv
  post_5 <- filter(d_ij, time == end_times)$surv_post_tx
  
  if (length(wait_5) == 0){
     wait_5 <- NA
  }
  
  if (length(post_5)==0){
     post_5 <- NA
  }
  
  s_benefit[[1]] <- wait_5
  
  s_benefit[[2]] <- post_5
  
    return(s_benefit)

}

Distribution of survival benefit at five years for each center (three-status system)

Warnings:

  • this loop takes advantage of parallel processing and will use most of your cores.
  • Despite this expect long computational times.
detectCores()

no_cores <- detectCores() - 2
# Initiate cluster
cl <- makeCluster(no_cores,  type="FORK")

center_loop <- function(centers, recips, cl){

  #output tibbles
  wait_surv <- tibble(recips = recips)
  post_tx_surv <- tibble(recips = recips)
  
  for (c in centers) {
    cur_center <- as.numeric(c)
    print(paste0("currently calculating for center ", c))
    
    B_i <- parSapply(cl, r_list, 
                     function(x) ben_wait_tx(j = x, 
                                             df = to_model, 
                                             base_hz = basehz, 
                                             model = three_status, 
                                             i = cur_center))
    
    B_trans <- matrix(B_i, nrow = 2, ncol = length(recips)) %>% t()
    B_tib <-  as.tibble(B_trans) 


    wait <- B_tib %>% select(V1) %>% cbind(recips)
    colnames(wait) <- c(c, "recips")
    
    post_tx <- B_tib %>% select(V2) %>% cbind(recips)
    colnames(post_tx) <- c(c, "recips")
    
    wait_surv <- wait_surv %>% left_join(wait, by = "recips")
    
    post_tx_surv <- post_tx_surv %>% left_join(post_tx, by = "recips")
    

  }
  benefit <- list(wait_surv, post_tx_surv)
  
  return(benefit)
}


r_list <- unique(filter(to_model, tx ==1)$PX_ID)
c_list <- as.numeric(row.names(ranef(three_status)[[1]]))


by_time_tibbles <- center_loop(c_list, r_list, cl)


stopCluster(cl)

five_yr_wait <- by_time_tibbles[[1]]

five_yr_post <- by_time_tibbles[[2]]

Make datasets for use in Figures and Results Section

#recipients
recips <- to_model %>% group_by(PX_ID) %>% filter(tx == 1) %>% ungroup()

#marginal distribution of benefit of transplant
marginal_hazards <- mapply(hr_tx_ij, i = recips$center, j = recips$PX_ID)

marginal_waits_posts <- mapply(ben_wait_tx, i = recips$center, j = recips$PX_ID)

marginal_waits <- marginal_waits_posts[1,]
marginal_posts <- marginal_waits_posts[2,]

pop_tx_hz <- recips %>% cbind(marginal_hazards, marginal_waits, marginal_posts) %>% 
  mutate(log_hazard = marginal_hazards, 
         hr = exp(log_hazard),
         benefit= marginal_posts- marginal_waits)

r_list <- unique(filter(to_model, tx ==1)$PX_ID)
c_list <- as.numeric(row.names(ranef(three_status)[[1]]))

center_OPO <- recips %>% select(center, OPO) %>% 
  group_by(center, OPO) %>% 
  summarise(num_tx = n()) %>% ungroup()

re_effects <- data.frame(ranef(three_status)[[1]])

re_effects$center <- row.names(re_effects)

colnames(re_effects)[2] <- "tx_re"

#make a center level dataset of random effects
center_re <- center_OPO %>% 
  left_join(re_effects %>% mutate(center = as.numeric(center))) %>% 
  mutate(tx_exp = exp(tx_re),
         benefit = tx_re-Intercept,
         intercept_exp = exp(Intercept)) %>% ungroup()

center_re <- center_re %>% left_join(five_year_means)

#calculate the minimum and maximum center
min_tx_exp <- min(center_re$tx_exp)

max_tx_exp <- max(center_re$tx_exp)

min_int_exp <- min(center_re$intercept_exp)

max_int_exp <- max(center_re$intercept_exp)
#make benefit dataframe- hypothetical estimates as if all recipients were transplanted at the center
colnames(five_yr_wait) <- c("recips", c_list)
colnames(five_yr_post) <- c("recips", c_list)

M <- merge(five_yr_post,five_yr_wait,by="recips")

ben_five_year_only <- M[,grepl("*\\.x$",names(M))] - M[,grepl("*\\.y$",names(M))]

cbind(M[,1,drop=FALSE],ben_five_year_only)
remove(M)

five_year_waits <- five_yr_wait %>% select(-recips) %>% 
  summarise_all(mean, na.rm =TRUE) %>% 
  gather(value = mean_five_year_wait, key = center) %>% 
  select(center, mean_five_year_wait) %>% mutate(center = as.numeric(center))

five_year_posts <- five_yr_post %>% select(-recips) %>% 
  summarise_all(mean, na.rm =TRUE) %>% 
  gather(value = mean_five_year_post, key = center) %>% 
  select(center, mean_five_year_post) %>% mutate(center = as.numeric(center))


#center level dataset of summary statistics for case-mix adjusted 
#five-year mean waitlist, post-transplant, and survival benefits
five_year_means <- ben_five_year_only %>% 
  summarise_all(funs(mean, 
                     median, 
                     sd, 
                     IQR, 
                     lowQR = quantile(., probs=0.25), 
                     upQR = quantile(., probs=0.75)), na.rm = TRUE) %>%
  gather(key = "key", value = "value") %>%
  separate(key, c("center", "stat"), sep = "_") %>%
  spread(stat, value) %>% 
  mutate(center = numextract(center), mean_five_year = mean) %>% select(-mean) %>%
  left_join(five_year_waits, by = "center") %>% 
  left_join(five_year_posts, by = "center") %>%  
  left_join(center_OPO, by = "center")

five_year_means <- five_year_means %>%
  mutate(se_mean = sd/sqrt(num_tx),
         upper_ci = mean_five_year + 1.96*se_mean,
         lower_ci = mean_five_year - 1.96*se_mean,
         sig_better = if_else(lower_ci >mean(five_year_means$mean_five_year), 1, 0),
         sig_worse = if_else(upper_ci <mean(five_year_means$mean_five_year), 1, 0),
         center_performance = case_when(
           lower_ci >mean(five_year_means$mean_five_year) ~ "High",
           upper_ci <mean(five_year_means$mean_five_year) ~ "Low",
           TRUE ~ "Average"
         ), center_performance = factor(center_performance, 
                                        levels = c("Low", "Average", "High")))
#marginal distribution of benefit of transplant under six status model
marginal_hazards_6_stat <- mapply(hr_tx_ij, 
                                  i = recips$center, 
                                  j = recips$PX_ID, 
                                  MoreArgs = list(model = six_status))

marginal_waits_posts_6_stat <- mapply(ben_wait_tx, 
                                      i = recips$center, 
                                      j = recips$PX_ID,  
                                      MoreArgs = list(base_hz = basehz_six_stat,
                                                      model = six_status))

marginal_waits_6_stat <- marginal_waits_posts_6_stat[1,]
marginal_posts_6_stat <- marginal_waits_posts_6_stat[2,]


pop_tx_hz_6_stat <- recips %>% cbind(marginal_waits_6_stat, marginal_posts_6_stat) %>% 
  mutate(benefit_6 = marginal_posts_6_stat - marginal_waits_6_stat)

#not run- save workspace image
#save.image("model_fit_06_15_w_benefits.RData")

Figures

Figure 2: Between-center Variation in the Survival Benefit Associated with Heart Transplantation

to_plot <- five_year_means %>% arrange(mean_five_year) %>% mutate(index = row_number())


g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}

catepillar <- ggplot(to_plot, aes(x = index, 
                    y = mean_five_year*100, 
                    ymin = lower_ci*100, 
                    ymax = upper_ci*100, 
                    color = center_performance)) + 
  geom_point() + 
  geom_errorbar() + 
  scale_color_manual(name = "Center benefit:",
                     values= c("red3","black","navyblue"), 
                     guide = guide_legend()) +
  
  scale_x_continuous(breaks = c(1, 113)) +
  scale_y_continuous(breaks = seq(25, 60, 5), limits = c(25, 60)) +
  labs(y = "Absolute five-year survival benefit \nof heart transplant (%)",
       x = "Center", color = "") +  
  theme_few() + 
  theme(axis.title = element_text(), 
        axis.title.y = element_text(), 
        legend.title=element_text(size=12),
        legend.text=element_text(size=12),
        panel.grid.major.y = element_line(color = "gray", size = 0.25),
        legend.position="bottom") 


box <- ggplot(to_plot %>% mutate(all = " "), aes(x = all, y = 100*mean_five_year)) + 
  geom_boxplot() +
  stat_boxplot(geom = "errorbar", width = 0.5) +
  geom_point(y = mean(to_plot$mean_five_year)*100, 
             aes(x =all, shape = "mean"), 
             size=4, fill = "gray", alpha = 0.5 )+ 
  theme_few() +
  labs(x = " ", shape = " ") +
  scale_shape_manual(values = 23) + 
  theme(
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.text.y =  element_blank(),
        legend.title=element_text(size=12),
        legend.text=element_text(size=12),
        panel.grid.major.y = element_line(color = "gray", size = 0.25),
        legend.position= "bottom",
        legend.justification='left') +
  scale_y_continuous(limits = c(25, 60), breaks = seq(25, 60, 5))

fig_2 <- grid.arrange(catepillar, box,
                         nrow=1, widths = c(1, 0.25))


num_high <- table(five_year_means$center_performance)["High"][[1]]

num_low <- table(five_year_means$center_performance)["Low"][[1]]

max_benefit <- comma_2(100*max(to_plot$mean_five_year))


min_benefit <- comma_2(100*min(to_plot$mean_five_year))


high_qrt_5 <- comma_2(100*quantile(to_plot$mean_five_year, probs = 0.75))

low_qrt_5 <- comma_2(100*quantile(to_plot$mean_five_year, probs = 0.25))

median_5 <- comma_2(100*median(to_plot$mean_five_year))

ggsave( "fig_2.pdf", plot = fig_2, width = 6, height = 4)

Between-center variation in the absolute improvement in mean five-year survival associated with heart transplantation. Caterpillar plot (left) of center estimates case-mix adjusted for time from listing to transplant, waitlist Status, year of listing, donor quality, and cold ischemic time. Ninety-five percent confidence intervals are constructed using the variance of the distribution of five-year survival estimates for the entire study population and the number of transplants performed at each center during the study period. Compared to the mean center, 31 centers (27%) had significantly higher survival benefit and 30 centers (27%) had lower benefit.

The adjusted five-year survival benefit varied substantially by center, ranging from 30% to 55%, median 43 and IQR [40% - 47%] (Box plot, right). Whiskers represent smallest and largest observations within 1.5 times the IQR of the hinges, points represent outliers beyond this range. The mean of center five-year survival benefits is represented by a gray diamond.

Figure 3: Relationship between Candidate Survival on the Waitlist, Recipient Post-Transplant Outcomes, and the Benefit of Heart Transplantation


panel_A <- ggplot(data = center_re, 
                  aes(x = 100*mean_five_year_wait, 
                      y = 100*mean_five_year)) + 
  geom_point(aes(color = center_performance), size = 2.5, alpha = 0.9) +
  #annotate("label", x = 25, y = 30, label = paste0("r = ", cor_model), size = 5) + 
  scale_x_continuous(name = "Five-year survival without transplant (%)", 
                     limits = c(18, 44), 
                     breaks =  c(20, 25, 30, 35, 40)) + 
  scale_y_continuous(name = "Center five-year surival benefit (%)", 
                     limits = c(27, 60), breaks = seq(30, 60, 5)) + 
  scale_color_manual(name = "Center benefit:", 
                     values = c("red3","black","navyblue")) +
  theme_few() + 
  ggtitle("Panel A") + 
  theme(legend.key = element_rect(fill = "white"), 
        legend.background = element_rect(fill = "white"),
        legend.direction = "horizontal",
        panel.border = element_blank(),
        axis.line = element_line(color = "black", size = 0.25),
        plot.title = element_text(hjust = 0.5),
        legend.title=element_text(size=12),
        legend.text=element_text(size=12),
        legend.box.background = element_rect(colour = "black"))



mylegend <- g_legend(panel_A)



panel_B <- ggplot(data = center_re, 
                  aes(x = mean_five_year_post*100, y = 100*mean_five_year)) + 
  geom_point(aes(color = center_performance), size = 2.5, alpha = 0.9) +
  scale_x_continuous(name = "Five-year post-transplant survival (%)", 
                     limits = c(63, 89), 
                     breaks =  c(65, 70, 75, 80, 85)) +
  scale_y_continuous(limits = c(27, 60), breaks = seq(30, 60, 5)) +
scale_color_manual(values = c("red3","black","navyblue")) +
  theme_few() +
  ggtitle("Panel B")+
  theme(axis.title.y = element_blank(), 
        panel.border =  element_blank(),
        axis.line = element_line(color = "black", size = 0.25),
        legend.position="none",
        panel.grid.major.y = element_line(color = "gray", size = 0.25),
        plot.title = element_text(hjust = 0.5))



fig_3 <- grid.arrange(
  arrangeGrob(panel_A + theme(legend.position="none", 
                      panel.grid.major.y = element_line(color = "gray", size = 0.25)),
                         panel_B,
                         nrow=1, widths = c(1, 0.95)),
                      mylegend, 
             nrow=2,heights=c(10, 2.2))



slope_waitlist <- lm(mean_five_year ~ mean_five_year_wait, 
                                         data = center_re)

slope_post <- lm(mean_five_year ~ mean_five_year_post, 
                                         data = center_re)

pct_benefit_increase_per_neg_10 <- comma_2(
  10*-slope_waitlist$coefficients[[2]])

ci_slope_wait_low <- comma_2(10*-confint(slope_waitlist, 'mean_five_year_wait', level=0.95)[1,1])

ci_slope_wait_up <- comma_2(10*-confint(slope_waitlist, 'mean_five_year_wait', level=0.95)[1,2])


pct_benefit_increase_post <- comma_2(10*slope_post$coefficients[[2]])


ci_slope_post_low <- comma_2(10*-confint(slope_post, 'mean_five_year_post', level=0.95)[1,1])

ci_slope_post_up <- comma_2(10*-confint(slope_post, 'mean_five_year_post', level=0.95)[1,2])

ggsave("fig_3.pdf", plot = fig_3)

Mean five-year survival without transplant, five-year post-transplant survival, and five-year survival benefit for each US heart transplant center. There was a significant relationship between the Status-adjusted medical urgency of candidates listed by each center (as measured by risk of death on the waitlist) and the benefit of transplantation measured by five-year survival benefit (left panel). For every 10% decrease in expected candidate waitlist surival, there was a 6.2% increase in estimated survival benefit associated with heart transplant (95% CI 5.2% - 7.3%). In contrast, there was no significant relationship between post-transplant survival and benefit (+1.5%, 95% CI -3.8%- 0.83%) (right panel).

Figure 4A: Five-year Survival Benefit Associated with Heart Transplantation by Three-status at Transplantation

five_yr_by_status <- pop_tx_hz %>% 
  group_by(three_status) %>%
  summarise(
    number = n(), 
    median = 100*median(benefit, na.rm = TRUE),
    upper_IQR = 100*quantile(benefit, probs = 0.75, na.rm = TRUE),
    lower_IQR = 100*quantile(benefit, probs = 0.25, na.rm = TRUE),
    mean = 100*mean(benefit, na.rm = TRUE),
    mean_waitlist = 100*mean(marginal_waits, na.rm = TRUE),
    mean_post = 100*mean(marginal_posts, na.rm = TRUE)
  )

five_yr_by_status



three_box <- ggplot(data = pop_tx_hz %>%
                      mutate(x_labels = case_when(
                        three_status == "Status 1A" ~ paste0("Status 1A\nN =", comma_2(filter(five_yr_by_status, three_status == "Status 1A")$number)),
                        three_status == "Status 1B" ~ paste0("Status 1B\nN =", comma_2(filter(five_yr_by_status, three_status == "Status 1B")$number)),
                        three_status == "Status 2" ~ paste0("Status 2\nN =", comma_2(filter(five_yr_by_status, three_status == "Status 2")$number))
                      )), 
  aes(y = 100*benefit, x=x_labels, color = three_status, fill = three_status)) + 
  geom_dotplot(binaxis = "y", 
               stackdir='center', 
               binwidth =  1, dotsize =  0.2, stackratio = .5) + 
  guides(color=FALSE, fill = FALSE) +
  labs(y = "Absolute 5-year survival benefit (%)", fill = "") +
  scale_y_continuous(limits = c(-5, 100)) + 
  theme_few() + 
  theme(axis.title.x = element_blank(),
        panel.grid.major.y = element_line(color = "gray", size = 0.25)) +
  scale_x_discrete(expand = expand_scale( mult = c(0.5, 0.2))) +
  scale_color_brewer(palette = "Set1", direction = -1) +
  scale_fill_brewer(palette = "Set1", direction = -1) +
  stat_boxplot(aes(x = x_labels, y = 100*benefit), 
               geom = "errorbar", 
               color = "black", 
               width = 0.25, lwd=0.75) +
  geom_boxplot(aes(x = x_labels, y = 100*benefit), 
               alpha = 0, color = "black", 
               outlier.shape = NA, 
               width = 0.5, lwd=0.75, fatten = 1.5)

three_box

ggsave("fig_4A.eps", plot = three_box, width = 8, height = 5)

Dot and box plots of estimated five-year survival benefit associated with heart transplantation for adult recipients by Status at transplantation between 2006-2015. There were 11,227 Status 1A recipients with median benefit from transplant of 59%, [IQR 54- 62%]. There were 7,250 Status 1B recipients with median benefit from transplant of 27%, [IQR 23- 31%]. In addition, there were only 1,338 Status 2 recipients with median benefit from transplant of 14%, [IQR 10- 17%]. Within priority Status groups, the standard deviation in the five-year survival benefit associated with transplant was 5.5% with the majority (76%) of the variation amongst recipients attributable to center-level effects and the remaining 24% attributable to variation in transplant year, waiting time, donor quality and ischemic time.

Figure 4B: Five-year Survival Benefit Associated with Heart Transplantation by Six-status at Transplantation



line_thickness <- 0.55
fatten_level <- 1.5

five_yr_by_six_status <- pop_tx_hz_6_stat %>%
  group_by(six_status) %>%
  summarise(
    number = n(), 
    median = 100*median(benefit_6, na.rm = TRUE),
    upper_IQR = 100*quantile(benefit_6, probs = 0.75, na.rm = TRUE),
    lower_IQR = 100*quantile(benefit_6, probs = 0.25, na.rm = TRUE),
    mean = 100*mean(benefit_6, na.rm = TRUE),
    mean_waitlist = 100*mean(marginal_waits_6_stat, na.rm = TRUE),
    mean_post = 100*mean(marginal_posts_6_stat, na.rm = TRUE)
  )



g1 <- ggplot(pop_tx_hz_6_stat %>%
                    filter(six_status == 1) %>%
                    mutate(six_status = paste0("Status 1\nN =", comma_2(filter(five_yr_by_six_status, six_status == 1)$number)))) + 
  geom_dotplot(aes(x = six_status, y = 100*benefit_6),
               color = RColorBrewer::brewer.pal(3, "Set1")[[3]],
               fill = RColorBrewer::brewer.pal(3, "Set1")[[3]],
               binaxis = "y", stackdir = "center", 
               method="dotdensity", stackgroups = T, binpositions="all", 
               binwidth =  1, dotsize =  0.2, stackratio = .5) +
    theme_few() +theme(axis.title.x = element_blank(), 
                       panel.border=element_blank(), 
                       axis.line = element_line(color="black", size = 0.25),
                       legend.position = "none",
                       plot.margin = margin(0,-4,0,2),
                       panel.grid.major.y = element_line(color = "gray", size = 0.25)) +
  scale_y_continuous(name = "Absolute 5-year survival benefit (%)", limits = c(-5, 100)) +
  stat_boxplot(aes(x = six_status, y = 100*benefit_6),  
               geom = "errorbar", color = "black", 
               width = 0.25, lwd=line_thickness) + 
  geom_boxplot(aes(x = six_status, y = 100*benefit_6), 
               fill = "gray", alpha = 0, color = "black", 
               outlier.shape = NA, width = 0.5, 
               lwd=line_thickness, fatten = fatten_level) 


for (i in c(2,3)){
  assign(paste0("g", i), ggplot(pop_tx_hz_6_stat %>%
                    filter(six_status == i) %>%
                    mutate(six_status = case_when(
                      six_status == 1 ~paste0("Status 1\nN =", comma_2(filter(five_yr_by_six_status, six_status == 1)$number)),
                      six_status == 2 ~paste0("Status 2\nN =", comma_2(filter(five_yr_by_six_status, six_status == 2)$number)),
                      six_status == 3 ~paste0("Status 3\nN =", comma_2(filter(five_yr_by_six_status, six_status == 3)$number)),
                      six_status == 4 ~paste0("Status 4\nN =", comma_2(filter(five_yr_by_six_status, six_status == 4)$number)),
                      six_status == 6 ~paste0("Status 6\nN =", comma_2(filter(five_yr_by_six_status, six_status == 6)$number))
                      ))) + 
  geom_dotplot(aes(x = six_status, y = 100*benefit_6),
               color = RColorBrewer::brewer.pal(3, "Set1")[[3]],  fill = RColorBrewer::brewer.pal(3, "Set1")[[3]],
               binaxis = "y", stackdir = "center", method="dotdensity", stackgroups = T, binpositions="all", 
               binwidth =  1, dotsize =  0.2, stackratio = .5) +
    labs(fill = "", color = "") + 
    theme_few() +theme(axis.title.x = element_blank(),
                       panel.border=element_blank(),
                       legend.position = "bottom",
                       axis.line =  element_line(color="black", size = 0.25),
                       axis.line.y = element_blank(),
                       axis.ticks.y = element_blank(),
                       axis.title.y = element_blank(),
                       axis.text.y =element_blank(),
                       plot.margin = margin(0,-4,0,-4),
                       panel.grid.major.y = element_line(color = "gray", size = 0.25))+ 
      scale_y_continuous(limits = c(-5, 100)) +
      scale_color_brewer(palette = "Set1", direction = 1) +
    scale_fill_brewer(palette = "Set1", direction = 1) +
  stat_boxplot(aes(x = six_status, y = 100*benefit_6),  
               geom = "errorbar", color = "black", 
               width = 0.25, lwd=line_thickness) + 
  geom_boxplot(aes(x = six_status, y = 100*benefit_6), 
               fill = "gray", alpha = 0, color = "black", 
               lwd=line_thickness, fatten = fatten_level) 
  )
}


for (i in c(4, 6)){
  assign(paste0("g", i), ggplot(pop_tx_hz_6_stat %>%
                    filter(six_status == i) %>%
                    mutate(six_status = case_when(
                      six_status == 1 ~paste0("Status 1\nN =", comma_2(filter(five_yr_by_six_status, six_status == 1)$number)),
                      six_status == 2 ~paste0("Status 2\nN =", comma_2(filter(five_yr_by_six_status, six_status == 2)$number)),
                      six_status == 3 ~paste0("Status 3\nN =", comma_2(filter(five_yr_by_six_status, six_status == 3)$number)),
                      six_status == 4 ~paste0("Status 4\nN =", comma_2(filter(five_yr_by_six_status, six_status == 4)$number)),
                      six_status == 6 ~paste0("Status 6\nN =", comma_2(filter(five_yr_by_six_status, six_status == 6)$number))
                      ))) + 
  geom_dotplot(aes(x = six_status, y = 100*benefit_6, color = three_status, fill=three_status),
               binaxis = "y", stackdir = "center", 
               method="dotdensity", stackgroups = T, binpositions="all", 
               binwidth =  1, dotsize =  0.2, stackratio = .5) +
    labs(fill = "Status in 3 tier system:", color = "Status in 3 tier system:") + 
    theme_few() +theme(axis.title.x = element_blank(),
                       panel.border=element_blank(),
                       legend.position = "bottom",
                       axis.line =  element_line(color="black", size = 0.25),
                       axis.line.y = element_blank(),
                       axis.ticks.y = element_blank(),
                       axis.title.y = element_blank(),
                       axis.text.y =element_blank(),
                       legend.title=element_text(size=11),
                       legend.text=element_text(size=11),
                       legend.background = element_blank(),
                        legend.box.background = element_rect(colour = "black"),
                       plot.margin = margin(0,-4,0,-4),
                       panel.grid.major.y = element_line(color = "gray", size = 0.25))+ 
      scale_y_continuous(limits = c(-5, 100)) +
      scale_color_brewer(palette = "Set1", direction = -1) +
    scale_fill_brewer(palette = "Set1", direction = -1) +
  stat_boxplot(aes(x = six_status, y = 100*benefit_6),  
               geom = "errorbar", color = "black", 
               width = 0.25, lwd=line_thickness) + 
  geom_boxplot(aes(x = six_status, y = 100*benefit_6), 
               fill = "gray", alpha = 0, 
               color = "black", outlier.shape = NA, 
               width = 0.5, lwd=line_thickness, fatten = fatten_level)
  )
}

mylegend <- g_legend(g4)



Fig_4B <- grid.arrange(
  arrangeGrob(g1 + theme(legend.position="none",
                         panel.grid.major.y = element_line(color = "gray", size = 0.25)),
              g2 + theme(legend.position="none", 
                         panel.grid.major.y = element_line(color = "gray", size = 0.25)),
              g3 + theme(legend.position="none", 
                         panel.grid.major.y = element_line(color = "gray", size = 0.25)),
              g4 + theme(legend.position="none", 
                         panel.grid.major.y = element_line(color = "gray", size = 0.25)),
              g6 + theme(legend.position="none", 
                         panel.grid.major.y = element_line(color = "gray", size = 0.25)),
                         nrow=1, widths = c(0.5, 0.3, 0.7, 1.2, 0.8)),
                      mylegend, 
             nrow=2,heights=c(10, 2.2)) 


ggsave("fig_4B.eps", plot = Fig_4B, width = 10, height = 5)

Dot and box plot of estimated five-year survival benefit associated with heart transplantation for adult recipients by projected six-status at transplantation between 2006-2015. Dot color corresponds to three-status at transplant, x-axis corresponds to re-assigned six-tier Status. There would have been 255 Status 1 recipients with median benefit from transplant of 69%, [IQR 65- 71%], 1,254 Status 2 recipients with median benefit from transplant of 65%, [IQR 61- 67%], 6,255 Status 3 recipients with median benefit from transplant of 49%, [IQR 46- 53%], 11,000 Status 4 recipients with median benefit from transplant of 28%, [IQR 24- 31%], and 1,051 Status 6 recipients with median benefit from transplant of 14%, [IQR 10- 17%]. Whiskers represent smallest and largest observations within 1.5 times the IQR of the hinges, points represent outliers beyond this range. When re-classifying recipients from 2006-2015 based on new Status 1-6 system, 6,255 (56%) Status 1A recipients met Status 3 critieria, 1,254 Status 2 critieria (11%) and 255 met Status 1 criteria (2%). A total of 3,462 (31%) of Status 1A recipients would have been downgraded to Status 4 because of violation of the cardiogenic shock requirement at the time of transplant. All 7,250 Status 1B recipients were re-assigned to Status 4. Two-hundred and twenty-eight (22%) low priority Status 2 (three-status system) would have been assigned the higher Status 4 because of restrictive cardiomyopathy, congenital heart disease, hypertrophic cardiomyopathy, or amyloidosis. The recipients are the same in both the three-status and six-status models, however, the increased number of tiers in the six-tier model allows for wider variation in estimated survival benefits. Compared to the three-status system, the within-status standard deviation of five-year survival benefit decreased from 5.5% to 4.9%. The majority (66%) of within-status variation in survival benefit was still attributable to centers, with the remaining 34% attributable to variation in transplant year, waiting time, donor quality and ischemic time.

Text of Results Section

Basic demographics


#for eTable4
cand_thor <- haven::read_sas("SAF 2018 Q3/cand_thor.sas7bdat", NULL) %>%  
  haven::zap_formats() %>% haven::zap_labels() 



init_lists <- to_model %>% group_by(PX_ID) %>%
  filter(row_number()==1) %>% 
  ungroup() %>% 
  mutate(PX_ID = as.numeric(PX_ID)) %>%left_join(cand_thor, by = "PX_ID")

mean_age <- mean(init_lists$CAN_AGE_AT_LISTING)

pct_female <- 100*(init_lists %>% filter(CAN_GENDER == "F") %>% nrow())/(init_lists %>% nrow())

Of 29,172 candidates (mean age, 52; 26% women) listed at 113 centers.

Between-center Variation in the Survival Benefit Associated with Heart Transplantation


#population estimates

##HR
pop_mean_hr <- comma_2(mean(pop_tx_hz$hr))
up_IQR_hr <- comma_2(quantile(pop_tx_hz$hr, probs = 0.75))
low_IQR_hr <- comma_2(quantile(pop_tx_hz$hr, probs = 0.25))

##five-year surival benefit
mean_benefit <- comma_2(100*mean(pop_tx_hz$benefit, na.rm = TRUE))
benefit_25 <- comma_2(100*quantile(pop_tx_hz$benefit, na.rm = TRUE, probs = 0.25))
benefit_75 <- comma_2(100*quantile(pop_tx_hz$benefit, na.rm = TRUE, probs = 0.75))

##five-year waitlist
mean_wait <- comma_2(100*mean(pop_tx_hz$marginal_waits, na.rm = TRUE))
wait_25 <- comma_2(100*quantile(pop_tx_hz$marginal_waits, na.rm = TRUE, probs = 0.25))
wait_75 <- comma_2(100*quantile(pop_tx_hz$marginal_waits, na.rm = TRUE, probs = 0.75))



##five-year post-transplant
mean_post <- comma_2(100*mean(pop_tx_hz$marginal_posts, na.rm = TRUE))
post_25 <- comma_2(100*quantile(pop_tx_hz$marginal_posts, na.rm = TRUE, probs = 0.25))
post_75 <- comma_2(100*quantile(pop_tx_hz$marginal_posts, na.rm = TRUE, probs = 0.75))

Heart transplantation was associated with a mean 76% decrease in mortality risk compared to waiting without transplant (hazard ratio 0.24, interquartile range [IQR] 0.14-0.35). This risk reduction generated a mean 44% (IQR 27-59%) absolute improvement in five-year survival, increasing from 33% (IQR 17- 51%) without transplant to 77% (IQR 74-80%) with transplant (full model results in Table S2).


#Calculate the within-status variation in the benefit under the three-status system
B_model <- lmer(100*benefit ~  stat_1b + stat_2 + (1|center), data = pop_tx_hz)


benefit_var <- as.data.frame(VarCorr(B_model)) 

center_var <- filter(benefit_var, grp == "center")$vcov
residual_var <- filter(benefit_var, grp == "Residual")$vcov

tot_var <- center_var + residual_var

sd_3 <- comma_2((tot_var)^(1/2))


pct_variation_center <- comma_2(100*center_var/tot_var)

pct_other <- comma_2(100*(1- center_var/tot_var))

#difference and 95% CI


diff_95ci <- function(x, y, w=NULL){
  lm <- lm(y ~ x, weights = w)
  diff <- comma_2(lm$coefficients[[2]])
  confint(lm, level = 0.95)
  low_ci <- comma_2(confint(lm, level = 0.95)[2,1])
  up_ci <- comma_2(confint(lm, level = 0.95)[2,2])
  
  if (lm$coefficients[[2]]>0){
    return(paste0("+", diff, "; 95% CI, ", low_ci, " to ", up_ci))
  }
  
  paste0(diff, "; 95% CI, ", low_ci, " to ", up_ci)
}


diff_95ci_pct <- function(x, y, w=NULL){
  lm <- lm(y ~ x, weights = w)
  diff <- comma_2(100*lm$coefficients[[2]])
  confint(lm, level = 0.95)
  low_ci <- comma_2(100*confint(lm, level = 0.95)[2,1])
  up_ci <- comma_2(100*confint(lm, level = 0.95)[2,2])
  
  if (lm$coefficients[[2]]>0){
    return(paste0("+", diff, "%; 95% CI, ", low_ci, "% to ", up_ci, "%"))
  }
  
  paste0(diff, "%; 95% CI, ", low_ci, "% to ", up_ci, "%")
}


high_low <- five_year_means %>% filter(sig_better ==1 | sig_worse ==1)

high_improvement <- comma(100*summary(lm(mean_five_year ~ sig_better, 
                                         data = high_low, 
                                         weights = high_low$num_tx))$coefficients[,1][[2]])

low_benefit <- five_year_means %>% filter(sig_worse ==1)

low_wait <- comma(100*weighted.mean(low_benefit$mean_five_year_wait, 
                                    low_benefit$num_tx))

low_post <- comma(100*weighted.mean(low_benefit$mean_five_year_post, 
                                    low_benefit$num_tx))

low_B <- comma(100*weighted.mean(low_benefit$mean_five_year, 
                                 low_benefit$num_tx))

high_benefit <- five_year_means %>% filter(sig_better ==1)

high_wait <- comma(100*weighted.mean(high_benefit$mean_five_year_wait, 
                                     high_benefit$num_tx))

high_post <- comma(100*weighted.mean(high_benefit$mean_five_year_post, 
                                     high_benefit$num_tx))

high_B <- comma(100*weighted.mean(high_benefit$mean_five_year, 
                                  high_benefit$num_tx))


post_high_low <- diff_95ci_pct(x = high_low$center_performance, 
                               y = high_low$mean_five_year_post, 
                               w = high_low$num_tx)

wait_high_low <- diff_95ci_pct(x = high_low$center_performance, 
                               y = high_low$mean_five_year_wait, 
                               w = high_low$num_tx)

surv_ben_high_low <- diff_95ci_pct(x = high_low$center_performance, 
                                   y = high_low$mean_five_year, 
                                   w = high_low$num_tx)

Adjusted for Status, candidate risk of death without transplant varied from 29% lower (relative HR 0.71) to 63% greater (relative HR 1.63) relative to the average center. The reduction in mortality risk from heart transplantation also varied significantly by center, from a maximum 29% greater reduction in mortality (relative HR 0.71) to a minimum of 68% lower reduction (relative HR 1.68) (eFigure 2). In combination, these center effects led to wide variation in the case-mix adjusted survival benefit of heart transplantation: the mean improvement in estimated five-year survival ranged from 30% to 55% by center, IQR [40% - 47%] (Figure 2). For every 10% decrease in expected candidate five-year waitlist survival without transplantation, there was a 6.2% increase in estimated survival benefit from heart transplant (95% CI 5.2% to 7.3%, Figure 3A). In contrast, there was no significant relationship between post-transplant survival and benefit (+1.5%, 95% CI -3.8% to 0.83%) (Figure 3B).

Medical Urgency of Recipients at High and Low Survival Benefit Centers


#Status at transplant by center performance
stat_by_benefit <- pop_tx_hz %>%
  filter(tx ==1) %>%
  left_join(five_year_means %>% select(center, center_performance)) %>%
  filter(center_performance != "Average") %>%
  mutate(center_performance = droplevels(center_performance),
         six_status = factor(six_status, 
                             labels = c("Status 1", "Status 2", "Status 3", "Status 4", "Status 6")))

pct_1a_High <- comma_2(100*mean(filter(stat_by_benefit, center_performance == "High")$stat_1a))

pct_1a_Low <- comma_2(100*mean(filter(stat_by_benefit, center_performance == "Low")$stat_1a))

p_1a_by_center <- comma_p(summary(glm(data =stat_by_benefit, 
                                      stat_1a ~ center_performance), 
                                  family = binomial, link = logit)$coefficients[2,4])
pct_1a_diff <- diff_95ci_pct(stat_by_benefit$center_performance, stat_by_benefit$stat_1a, w = NULL)



#Calculate overtreatment fraction amongst non-cardiogenic shock candidates
over_rates<- recips %>% left_join(five_year_means) %>% 
  filter(six_status > 3 & center_performance != "Average") %>%
  mutate(over_1a = ifelse(three_status == "Status 1A", 1, 0))


over_low <- comma_2(100*mean(filter(over_rates, 
                                    center_performance == "Low" & six_status >3)$over_1a))

over_high <- comma_2(100*mean(filter(over_rates, 
                                     center_performance == "High" & six_status >3)$over_1a))

p_over <- comma_p(summary(glm(over_1a ~ center_performance, 
                              data = over_rates, 
                              family = binomial()))$coefficients[2,4])

over_diff <- diff_95ci_pct(x = over_rates$center_performance, y = over_rates$over_1a, w = NULL)

stat_by_benefit <- stat_by_benefit %>% 
  mutate(stat_just = fct_recode(stat_just, 
                                "Status 1A (MCS complication)" = "Status 1A - (MCS complication)"))


#Status 1A characteristics
stat_1a_recip_w_tx_hr <- stat_by_benefit %>% 
  filter(three_status == "Status 1A") %>%
  mutate(PX_ID = as.numeric(PX_ID)) %>% left_join(tx_hr, by = "PX_ID") %>%
  mutate(Gender = factor(CAN_GENDER, levels = c("F", "M")),
         Race = factor(CAN_RACE),
         Race = fct_lump(Race, n = 3),
        Race = fct_recode(Race,
                          "White" = "8",
                          "Black" = "16",
                          "Hispanic" = "2000", 
                          "Other" = "Other"),
        Diagnosis = case_when(
          CAN_DGN>999 & CAN_DGN<1007 ~ "Dilated cardiomyopathy, non-ischemic",
          CAN_DGN == 1007 | CAN_DGN ==1200 ~ "Ischemic cardiomyopathy",
          CAN_DGN>1048 & CAN_DGN< 1100 ~ "Restrictive cardiomyopathy",
          TRUE ~ "Other"
        ),
        Diagnosis = factor(Diagnosis, 
                           levels = c("Dilated cardiomyopathy, non-ischemic", 
                                      "Ischemic cardiomyopathy", 
                                      "Restrictive cardiomyopathy", 
                                      "Other")),
        Diabetes = case_when(
          CAN_DIAB_TY>1 & CAN_DIAB_TY<6 ~ "History of DM",
          CAN_DIAB_TY ==1 ~ "Non-diabetic",
          TRUE ~ "Unknown"
        ),
        female_gfr = if_else(CAN_GENDER == "F", 0.742, 1),
        black_gfr = if_else(Race == "Black", 1.21, 1),
        eGFR = 175*((REC_CREAT)^(-1.154))*(REC_AGE_AT_TX^(-0.203))*female_gfr*black_gfr,
        Renal_Function = case_when(
          REC_DIAL == "Y" ~ "Dialysis",
          eGFR >= 60 ~ "GFR >= 60 ml/min/1.73 m^2",
          eGFR>= 30 ~ "GFR >= 30 & <60 ml/min/1.73 m^2",
          eGFR < 30 ~ "GFR < 30 ml/min/1.73 m^2",
          TRUE ~ "Unknown"
        ),
        Renal_Function = if_else(is.na(Renal_Function)==TRUE, "Unknown", Renal_Function),
        body_surface_area = 0.007184*(REC_HGT_CM)^(0.725)*REC_WGT_KG^(0.425),
        Cardiac_Index = as.numeric(REC_CARDIAC_OUTPUT/body_surface_area),
        Functional_Status = case_when(
          REC_FUNCTN_STAT == 1 | (REC_FUNCTN_STAT>2069) ~"Limited Impairment, 10-30%",
          (REC_FUNCTN_STAT>2039 & REC_FUNCTN_STAT<2061) ~ "Moderate Impairment, 40-60%",
          (REC_FUNCTN_STAT>2000 & REC_FUNCTN_STAT<2031) ~ "Severe Impairment, 70-100%",
          TRUE ~ "Unknown"
        ),
        Functional_Status = ifelse(is.na(Functional_Status), "Unknown", Functional_Status),
        severe_impairment = ifelse(Functional_Status == "Severe Impairment, 70-100%", 1, 0),
        stat_1a_just = droplevels(stat_just),
        acute_mcs = ifelse(stat_1a_just == "Status 1A (MCS for shock)", 1, 0),
        lvad_comp = ifelse(stat_1a_just == "Status 1A (MCS complication)", 1, 0),
        pcwp_15 = ifelse(REC_PCW_MEAN < 15, 1, 0),
        pcwp_15 = ifelse(is.na(REC_PCW_MEAN), 0, pcwp_15),
         blood_type = factor(
           case_when(
             CAN_ABO %in% c("A", "A1", "A2") ~ "A",
             CAN_ABO %in% c("A1B", "A2B") ~ "AB",
             TRUE ~ CAN_ABO)
           ),
        payor = case_when(
          REC_PRIMARY_PAY %in% c(3,4,13) ~ "Medicare",
          REC_PRIMARY_PAY ==2 ~ "Medicaid",
          REC_PRIMARY_PAY == 1 ~ "Private",
          TRUE ~ "Other"
        )
  )

#PCWP < 15 
pct_under_15_PCWP_high <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                            center_performance == "High")$pcwp_15, 
                                     na.rm = TRUE))


pct_under_15_PCWP_low <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                            center_performance == "Low")$pcwp_15, 
                                     na.rm = TRUE))

pcwp_15_diff <- diff_95ci_pct(x = stat_1a_recip_w_tx_hr$center_performance, 
                              y = stat_1a_recip_w_tx_hr$pcwp_15)

#PCWP Mean
pct_REC_PCW_MEAN_High <- comma(mean(filter(stat_1a_recip_w_tx_hr, 
                                           center_performance == "High")$REC_PCW_MEAN, 
                                    na.rm = TRUE))

pct_REC_PCW_MEAN_Low <- comma(mean(filter(stat_1a_recip_w_tx_hr, 
                                          center_performance == "Low")$REC_PCW_MEAN, 
                                   na.rm = TRUE))

pcwp_mean_diff <-  diff_95ci(x = stat_1a_recip_w_tx_hr$center_performance, 
                             y = stat_1a_recip_w_tx_hr$REC_PCW_MEAN)


#functional impairment
pct_severe_impairment_High <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                                      center_performance == "High")$severe_impairment, 
                                               na.rm = TRUE))

pct_severe_impairment_Low <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                                     center_performance == "Low")$severe_impairment, 
                                              na.rm = TRUE))

severe_impair_diff <- diff_95ci_pct(x =stat_1a_recip_w_tx_hr$center_performance, 
                                    y =stat_1a_recip_w_tx_hr$severe_impairment)


#acute MCS use
pct_acute_mcs_High <- comma(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                              center_performance == "High")$acute_mcs, 
                                       na.rm = TRUE))

pct_acute_mcs_Low <- comma(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                             center_performance == "Low")$acute_mcs, 
                                      na.rm = TRUE))


acute_mcs_diff <- diff_95ci_pct(x = stat_1a_recip_w_tx_hr$center_performance, 
                                y = stat_1a_recip_w_tx_hr$acute_mcs)


#LVAD complications
pct_lvad_comp_High <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                              center_performance == "High")$lvad_comp, 
                                       na.rm = TRUE))

pct_lvad_comp_Low <- comma_2(100*mean(filter(stat_1a_recip_w_tx_hr, 
                                             center_performance == "Low")$lvad_comp, 
                                      na.rm = TRUE))

p_lvad_comp_by_center <- comma_p(summary(glm(data =stat_1a_recip_w_tx_hr, 
                                             lvad_comp ~ center_performance, 
                                             family = binomial))$coefficients[2,4])

lvad_comp_diff <- diff_95ci_pct(x = stat_1a_recip_w_tx_hr$center_performance, 
                                y = stat_1a_recip_w_tx_hr$lvad_comp)

#center volume and benefit association
volume_benefit_diff <- diff_95ci(x = five_year_means$num_tx, 
                                 y = 100*100*five_year_means$mean_five_year)

volume_wait_diff <- diff_95ci(x = five_year_means$num_tx, 
                              y = 100*100*five_year_means$mean_five_year_wait)

volume_post_diff <- diff_95ci(x = five_year_means$num_tx,
                              y = 100*100*five_year_means$mean_five_year_post)


lvad_rates <- to_model %>% 
  filter(tx ==1) %>%
  left_join(center_re %>% select(center, center_performance)) %>% 
  filter(center_performance != "Average") %>% 
  mutate(high_ben = ifelse(center_performance == "High", 1, 0))

pct_lvad_high <- comma_2(100*mean(filter(lvad_rates, 
                                              center_performance == "High")$cf_lvad, 
                                       na.rm = TRUE))

pct_lvad_low <- comma_2(100*mean(filter(lvad_rates, 
                                              center_performance == "High")$cf_lvad, 
                                       na.rm = TRUE))

Compared to average, 31 centers (27%) had significantly higher survival benefit and 30 centers (27%) had significantly lower benefit. At five-years, Status-adjusted post-transplant survival was similar at high and low-benefit centers (77.6% vs. 77.1%, +0.5%; 95% CI, -1.3% to 2.3%). However, estimated candidate survival without transplant was lower at high-benefit centers (29% vs 39%, -10%; 95% CI, -12% to -8.1%), leading to a larger five-year survival benefit (48.6% vs 38%, +11%; 95% CI, 9.3% to 12%). Compared to low-benefit centers, high-benefit centers used Status 1A qualifying therapies less frequently (50% vs. 63%, -13%; 95% CI, -15% to -11%, Table S3) and were less likely to treat candidates who did not meet hemodynamic requirements for cardiogenic shock with Status 1A qualifying IABPs or high-dose inotropes (25% vs. 31%, -5.1%; 95% CI, -7.2% to -3%). At the time of transplant, Status 1A candidates at high benefit centers had higher pulmonary capillary wedge pressures (mean 20.1 vs. 18.9 mmHg, +1.2; 95% CI, 0.7 to 1.6 and percentage less than 15 mmHg 25% vs. 32%, -7.1%; 95% CI, -9.2% to -4.9%), and worse functional status (55% vs. 42% with severe impairment requiring continuous hospitalization, (+13%; 95% CI, 11% to 15%) than low-benefit centers. High-benefit centers transplanted more recipients for acute hemodynamic decompensation requiring mechanical support (37.6% vs. 30.5%, +7.2%; 95% CI, 4.9% to 9.4%) and used the “device-related complication” Status 1A justification significantly less often (20% vs. 37%, -17%; 95% CI, -19% to -15%) (Table S4). At high benefit centers, 35% of Status 1A recipients had a BTT LVAD at the time of transplant compared to35% of recipients at low benefit centers (-14%; 95% CI, -16% to -12%). Across all centers, transplant volume was weakly associated with post-transplant survival (+0.59; 95% CI, 0.074 to 1.1), however was not associated with either candidate urgency (+0.49; 95% CI, -0.29 to 1.3) or survival benefit (+0.099; 95% CI, -0.56 to 0.75) (Figure S4).

The Association of Status and Survival Benefit in Three and Six-Tier Allocation Systems

#status switch table
status_switch <- pop_tx_hz %>% left_join(pop_tx_hz_6_stat) %>%
  group_by(six_status, three_status) %>% count() %>%
  spread(key = three_status, value = n) %>%
  mutate_all(funs(ifelse(is.na(.)==TRUE, 0, .)))

tot_1as <- sum(status_switch$"Status 1A")

tot_1bs <- sum(status_switch$"Status 1B")

tot_2s <- sum(status_switch$"Status 2")

Under the prior three-status heart allocation system, the most common Status at transplant was 1A (N =11,227, 57%) and heart transplantation for a Status 1A candidate conferred a mean five-year survival benefit associated with 58%, (IQR 54- 62%). Status 1B was the next most common (N = 7,250, 37%) with a mean five-year survival benefit associated with transplant of 27%, (IQR 23- 31%). There were only 1,338 candidates at Status 2 at the time of transplant (7%) with mean five-year survival benefit associated with transplant of 14%, (IQR 10- 17%) (Figure 4A). Overall, within a given priority Status at transplantation, the standard deviation in five-year survival benefit was 5.5% with the majority (76%) of the variation amongst recipients attributable to center-level effects and the remaining 24% attributable to variation in transplant year, waiting time, donor quality and ischemic time. When retrospectively re-classifying recipients from 2006-2015 based on new Status 1-6 system, 6,255 Status 1A recipients met Status 3 criteria (56%), 1,254 met Status 2 criteria (11%), and 255 met Status 1 criteria (2%). A total of 3,462 (31%) of Status 1A recipients would have been downgraded to Status 4 because of a violation of the cardiogenic shock requirement at the time of transplant. All 7,250 Status 1B recipients were re-assigned to Status 4. Two-hundred and twenty eight (22%) low priority Status 2 (three-status system) recipients would have been assigned to the higher Status 4 because of restrictive cardiomyopathy, congenital heart disease, hypertrophic cardiomyopathy, or amyloidosis. (eTable5). Estimated five-year survival benefit associated with transplant ranged from of 68% (Status 1) to 14% (Status 6) (Figure 4B). Compared to the three-status system, the within-status standard deviation of five-year survival benefit decreased from 5.5% to 4.9% but the majority (66%) was still attributable to centers. The between-center variance in the survival benefit of transplant on the log hazard ratio scale transplant decreased from 0.161 to 0.115, corresponding to a reduction in the between-center variance of absolute five-year survival benefit from 23% to 16%. (eTable6).


#Variation in log hazard of transplant in three and six-status models
var_tx_3_stat <- VarCorr(three_status)$center[2,2]

var_tx_6_stat <- VarCorr(six_status)$center[2,2]

#within-status variation in the five-year survival benefit under the six-status system
B_model_6 <- lmer(100*benefit_6 ~  factor(six_status) + (1|center), data = pop_tx_hz_6_stat)

benefit_var_6 <- as.data.frame(VarCorr(B_model_6)) 

center_var_6 <- filter(benefit_var_6, grp == "center")$vcov
residual_var_6 <- filter(benefit_var_6, grp == "Residual")$vcov

tot_var_6 <- center_var_6 + residual_var_6

sd_6 <- comma_2((tot_var_6)^(1/2))
  
pct_variation_center_6 <- comma_2(100*center_var_6/tot_var_6)

pct_other_6 <- comma_2(100*(1- center_var_6/tot_var_6))

When re-classifying recipients from 2006-2015 based on new Status 1-6 system, the majority (56%) of Status 1A recipients would have been Status 3, with a smaller group qualifying for Status 2 (11%) and very few meeting Status 1 criteria (2%). A substantial portion (31%) of Status 1A candidates would have been downgraded to Status 4 because of violation of the cardiogenic shock requirement. A small number of recipients (N = 288) would have been assigned a higher status because of restrictive cardiomyopathy (Table S5 for details). Five-year survival benefit from transplant ranged from of 68% (Status 1) to 14% (Status 6) (Figure 5B).

Compared to the three-status system, the within-status standard deviation of five-year survival benefit decreased from 5.5% to 4.9% but the majority (66%) was still attributable to centers. The between-center variance in the survival benefit of transplant on the log hazard scale decreased from 0.161 to 0.115 on log hazard ratio scale. The between-center variance in absolute 5-year survival benefit decreased from 23% to 16%. (Table S6).

Supplement

Figure S1: Details of prior and current heart allocation system

Current and future adult heart allocation. Schematic depiction of the shift from the current adult heart allocation system to the modified system. * Cardiogenic shock requirement applies. (Constructed with permission directly from the policy details in Organ Procurement and Transplantation Network1). Complete detail about each of the Status criteria are available at https://optn.transplant.hrsa.gov/media/1200/optn_policies.pdf#nameddest=Policy_06. Dischargeable vs. non-dischargeable ventricular support devices were distinguished via a list provided by the SRTR.

eFigure 2: Center-specific Survival Benefit Framework

#Survival benefit from transplantation for a Status 1A patient 
#transplanted at a center with a high benefit from transplant
top_c <- center_re %>% arrange(-benefit) %>% filter(row_number()==1)
top_c_tx_hr <- top_c$tx_exp
top_c_wt_risk <- top_c$intercept_exp
top_c <- top_c$center

best_ctr_recips <- unique(to_model %>% filter(center == top_c) %>% 
                            select(PX_ID)) %>% 
  left_join(to_model %>% select(PX_ID, tx, stat_1a, t_1, era_tx) %>% 
              group_by(PX_ID, tx) %>% 
              filter(tx ==1 & row_number() ==1)) %>% 
  filter(is.na(tx) == FALSE)

ex_pt_top <- best_ctr_recips[[156, "PX_ID"]]

t_tx <- best_ctr_recips[[156, "t_1"]]

hz_good <- exp(hr_tx_ij(model = three_status, 
                        df = to_model, i = top_c, j = ex_pt_top))

max_fup <- max(basehz$time)/365

ex_benefit <- ben_wait_tx(df = to_model, 
                          base_hz = basehz, 
                          model = three_status, j = ex_pt_top, i = top_c)
fiveyr_good <- comma_2(100*(ex_benefit[[2]]-ex_benefit[[1]]))
fiveyr_good_wait <- comma_2(100*ex_benefit[[1]])
fiveyr_good_tx <- comma_2(100*ex_benefit[[2]])

good_plot <- b_ij(df = to_model, base_hz = basehz, model = three_status, j = ex_pt_top, i = top_c) + 
 scale_x_continuous(limits = c(0, 5*365), breaks= seq(0, t_tx + 5*365, 365)) + 
  scale_y_continuous(breaks= seq(0, 1, 0.2)) + 
  theme_economist_white() + 
  theme(axis.title = element_text(), 
        axis.title.y = element_text(), 
        legend.position="bottom", 
        legend.key = element_rect(fill = "white"), 
        legend.background = element_rect(fill = "white"), 
        legend.text = element_text(size = 12))


### Figure 2B: Survival benefit from transplantation for a "Status 1A" patient 
#transplanted at a center with a lower benefit from transplant
worst_c <- center_re %>% arrange(benefit) %>% filter(row_number()==1)
worst_c_tx_hr <- worst_c$tx_exp
worst_c_wt_risk <- worst_c$intercept_exp
worst_c <- worst_c$center

worst_c_recips <- unique(to_model %>% 
                           filter(center == worst_c) %>% 
                           select(PX_ID)) %>% 
  left_join(to_model %>% select(PX_ID, tx, stat_1a, t_1, era_tx) %>% 
              group_by(PX_ID, tx) %>% 
              filter(tx ==1 & row_number() ==1)) %>% 
  filter(is.na(tx) == FALSE)

ex_worst <- worst_c_recips[[30,"PX_ID"]]

t_tx_worst <- worst_c_recips[[30,"t_1"]]

ex_benefit_bad <- ben_wait_tx(df = to_model, 
                              base_hz = basehz, 
                              model = three_status,  
                              i = worst_c, 
                              j = ex_worst) 

fiveyr_bad <- comma_2(100*(ex_benefit_bad[[2]]-ex_benefit_bad[[1]]))
fiveyr_bad_wait <- comma_2(100*ex_benefit_bad[[1]])
fiveyr_bad_tx <- comma_2(100*ex_benefit_bad[[2]])

hz_bad <- exp(hr_tx_ij(model = three_status, df = to_model, i = worst_c, j = ex_worst))


bad_plot <- b_ij(df = to_model, 
                 base_hz = basehz, 
                 model = three_status,  
                 i = worst_c, j = ex_worst)+
  scale_x_continuous(limits = c(0, 5*365), 
                     breaks= seq(0, t_tx_worst + 5*365, 365)) + 
  scale_y_continuous(breaks= seq(0, 1, 0.2)) + 
  theme_economist_white() + 
  theme(axis.title = element_text(),
        axis.title.y = element_text(), legend.position="right")


#combine plots
g_legend<-function(a.gplot){
  tmp <- ggplot_gtable(ggplot_build(a.gplot))
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend <- tmp$grobs[[leg]]
  return(legend)}


mylegend <- g_legend(good_plot)


fig_2 <- grid.arrange(
                      arrangeGrob(good_plot + theme(legend.position="none"),
                         bad_plot + theme(legend.position="none", 
                                          axis.title.y = element_blank(), 
                                          axis.text.y = element_blank()),
                         nrow=1, widths = c(1, 0.9)),
                      mylegend, 
             nrow=2,heights=c(10, 2.2)) 


ggsave("efig_2.pdf", plot = fig_2)

Two example survival benefit predictions incorporating the timing of transplantation, candidate status, donor quality, ischemic time, and year of transplant.

The high-benefit center (Panel A) prioritizes Status 1A candidates at higher risk of wait-list mortality and transplantation at this center lowers risk more than average. Specifically, candidates listed by this center have a risk of death 63% higher than the average center (relative HR 1.63) and transplant lowers the risk of mortality 29% more than at the average center (HR 0.71). The combination of these two effects leads to a large 5-year survival benefit, improving survival (conditional upon reaching transplant) from 6.1% to 75% (+69% absolute gain) for this particular Status 1A patient transplanted after waiting 135 days.

In contrast, the patients transplanted at the low-benefit center (Panel B) are at lower risk of dying on the waitlist at baseline and transplantation at this center lowers risk less than average. Specifically, candidates listed by this center have a risk of death 26% lower than the average center (HR 0.74) and transplant lowers the risk of mortality 63% less than at the average center (HR 1.63). Despite the fact that the candidate has the same priority Status as the candidate in Panel A, the combination of these two effects leads to a smaller 5-year survival benefit, improving survival from 28% to 75% (+46% absolute gain) for transplanted after waiting 162 days.

Table S2: Three-status coxme results

print(three_status, digits =2)
Cox mixed-effects model fit by maximum likelihood
  Data: to_model
  events, n = 11058, 163240
  Iterations= 30 184 
                  NULL Integrated  Fitted
Log-likelihood -107600  -105890.7 -105702

                  Chisq  df p  AIC  BIC
Integrated loglik  3419  10 0 3399 3326
 Penalized loglik  3796 123 0 3550 2653

Model:  f_coxme 
Fixed coefficients
               coef exp(coef) se(coef)     z     p
tx           -1.953      0.14    0.045 -43.7 0.000
stat_2       -1.355      0.26    0.036 -37.1 0.000
stat_1b      -0.942      0.39    0.032 -29.8 0.000
tx_risky_don  0.260      1.30    0.028   9.3 0.000
era_tx       -0.054      0.95    0.030  -1.8 0.077
tx:stat_2     1.321      3.75    0.064  20.7 0.000
tx:stat_1b    0.904      2.47    0.044  20.7 0.000

Random effects
 Group  Variable  Std Dev Variance Corr  
 center Intercept  0.224   0.050   -0.509
        tx         0.238   0.057         

95% Confidence Intervals of coefficients

table_fe_results <- function(me_cox_1){
  fe_results_table <- tibble(covariate = character(), 
                             `log hazard ratio` = character(),
                             `95% CI` = character())
  fe <- fixef(me_cox_1)
  vc <- vcov(me_cox_1)
  for (i in seq_along(fe)){
    name <- names(fe[i])
    hr <- comma(unname(fe[i]))
    se <- sqrt(vc[i,i])
    ci <- paste0("(", comma(unname(fe[i]) - 1.96*se), 
                 ", ", 
                 comma(unname(fe[i]) + 1.96*se), ")")
    fe_results_table <- rbind(fe_results_table, 
                              tibble(covariate =name, 
                                     `log hazard ratio` = hr, 
                                     `95% CI` = ci))
  }
  return(fe_results_table)
}

table_fe_results(three_status)

#write_csv(table_fe_results(three_status), "three_status_fixed.csv")

to_plot <- plot_tx_effects(three_status) %>% 
  mutate(`Patient Status` = factor(covariate, 
                                   levels = c("tx", 
                                              "tx:stat_1b", 
                                              "tx:stat_2", 
                                              "tx_risky_don",
                                              "era_tx"), 
                                   labels =  c("Status 1A", 
                                               "Status 1B", 
                                               "Status 2",
                                               "High risk donor (Status 1A recipient)", 
                                               "Before 2010 (Status 1A recipient)"))) %>% 
  arrange(factor(covariate, 
                 levels = c("tx","tx:stat_1b", "tx:stat_2", "tx_risky_don","era_tx")))

ggplot(data = to_plot %>% 
         filter(!covariate %in% c("tx_risky_don","era_tx")), 
       aes(y = `Patient Status`, x = haz)) + 
  geom_point() + 
  geom_errorbarh(aes(xmin = low_ci, xmax = up_ci)) + 
  theme_fivethirtyeight() + 
  theme(axis.title = element_text(), axis.title.y = element_blank()) + 
  scale_x_continuous(limits = c(0,1), 
                     breaks = c(0, 0.25, 0.5, 0.75, 1),  
                     name = "Benefit heart transplantation (HR for Death)" )


tx_est <- comma_2(filter(to_plot, covariate == "tx")$haz)
tx_low <-comma_2(filter(to_plot, covariate == "tx")$low_ci)
tx_up <- comma_2(filter(to_plot, covariate == "tx")$up_ci)


stat_1b_est <- comma_2(filter(to_plot, covariate == "tx:stat_1b")$haz)
stat_1b_low <-comma_2(filter(to_plot, covariate == "tx:stat_1b")$low_ci)
stat_1b_up <- comma_2(filter(to_plot, covariate == "tx:stat_1b")$up_ci)


stat_2_est <- comma_2(filter(to_plot, covariate == "tx:stat_2")$haz)
stat_2_low <-comma_2(filter(to_plot, covariate == "tx:stat_2")$low_ci)
stat_2_up <- comma_2(filter(to_plot, covariate == "tx:stat_2")$up_ci)

ggsave("HR_transplant_model_1.pdf")

Hazard ratios of transplantation in the old 3-status system at transplantation as estimated by mixed-effects model, adjusted for donor risk, ischemic time, and year of transplant (see supplement for full model results).

Status 1A candidates had a hazard ratio of transplant 0.14 (95% CI 0.13-0.15), Status 1B candidates had a HR of 0.35 (95% CI 0.32-0.38) and Status 2 candidates had a HR of 0.53 (95% CI 0.47-0.61).

Figure S2: Smoothed baseline hazard function from time of listing


ggplot(data = basehz, aes(x=time/365, y = hz_t)) + 
  geom_smooth() + 
  labs(y = "Hazard") + 
  scale_x_continuous(name = "Years after listing", limits = c(0, 12), breaks = seq(0, 12, 2))

ggsave("base_hazard.pdf")

This baseline hazard function used to calculating the 5-year benefit was estimated non-parametrically using a kaplan-meier estimate. Immediately after listing for heart transplantation, candidates have increased hazard of death. More than 5 years after listing the hazard begins to rise again due to aging.

##Figure S3: Distribution of Survival Benefit at the Best and Worst Center, 2006-2015

best_center <- paste0(as.character(
  five_year_means[five_year_means$mean_five_year ==max(five_year_means$mean_five_year),]$center), ".x")

worst_center <- paste0(as.character(
  five_year_means[five_year_means$mean_five_year ==min(five_year_means$mean_five_year),]$center), ".x")

to_plot <- ben_five_year_only %>% select(best_center, worst_center) %>% 
  gather(key = center, value = five_year_benefit) %>% 
  mutate(ctr = if_else(center == best_center, "Best Center", "Worst Center"))

best_ctr_mean <- comma_2(
  100*mean(filter(to_plot, ctr == "Best Center")$five_year_benefit, na.rm = TRUE))

worst_ctr_mean <- comma_2(
  100*mean(filter(to_plot, ctr == "Worst Center")$five_year_benefit, na.rm =TRUE))

ggplot(to_plot, aes(x = five_year_benefit*100, fill = ctr)) + 
  geom_density(alpha = 0.5) + 
  scale_x_continuous(limits =  c(-25, 100), name = "5-year survival benefit (%)") +
  scale_fill_manual(values = c("blue", "red")) + 
  guides(fill = guide_legend(""))

ggsave("fig_S4.pdf")

Distribution of 5-year survival benefit if the best and worst center hypothetically had transplanted all recipients during the study time period. The best center had a mean five year survival benefit of 55% compared to only 30% at the lowest benefit center.

Table S3: Status at heart transplantation by center level of benefit

tangram::rmd(tangram::tangram("center_performance ~ three_status + six_status", stat_by_benefit, digits = 3))
N Low High Test Statistic
(N=5430) (N=6878)
three_status 12308 X22=238.05, P=<0.001
Status 1A 0.632 3430/5430 0.501 3447/6878
Status 1B 0.331 1800/5430 0.423 2908/6878
Status 2 0.037 200/5430 0.076 523/6878
six_status 12308 X24=285.82, P=<0.001
Status 1 0.012 66/5430 0.016 110/6878
Status 2 0.075 407/5430 0.051 349/6878
Status 3 0.383 2079/5430 0.265 1820/6878
Status 4 0.502 2725/5430 0.613 4214/6878
Status 6 0.028 153/5430 0.056 385/6878

Table S4: Status 1A recipient characteristics at time of transplant by center benefit

#Label Variables when necessary
Hmisc::label(stat_1a_recip_w_tx_hr$Cardiac_Index) <- "Cardiac Index (L/min/m^2)"
Hmisc::label(stat_1a_recip_w_tx_hr$REC_PCW_MEAN) <- "Mean Pulmonary Capillary Wedge Pressure (mmHg)"

Hmisc::label(stat_1a_recip_w_tx_hr$stat_1a_just) <- "Status 1A Justification at Transplant"

tangram::rmd(tangram::tangram("center_performance ~ benefit + marginal_posts + marginal_waits +  t_1 + REC_AGE_AT_TX + REC_BMI + Gender + Race + Diagnosis + Diabetes + Renal_Function + Functional_Status + Cardiac_Index + REC_PCW_MEAN + stat_1a_just + payor", data = stat_1a_recip_w_tx_hr))
N Low High Test Statistic
(N=3430) (N=3447)
benefit 6836 0.505 0.534 0.558 0.606 0.635 0.651 F1,6834=17466.59, P=<0.001
marginal_posts 6836 0.740 0.774 0.806 0.740 0.776 0.799 F1,6834=0.40, P=0.528
marginal_waits 6836 0.220 0.241 0.262 0.120 0.138 0.167 F1,6834=13817.14, P=<0.001
t_1 6877 43 138 374 16 56 213 F1,6875=337.56, P=<0.001
Age at TX 6877 45 55 62 45 55 62 F1,6875=0.61, P=0.436
BMI: 6866 23.8 27.2 31.0 23.3 26.5 30.1 F1,6864=30.68, P=<0.001
Gender : M 6877 0.788 2703/3430 0.774 2668/3447 X21=1.98, P=0.159
Race 6877 X23=28.01, P=<0.001
White 0.655 2246/3430 0.634 2186/3447
Black 0.226 775/3430 0.206 709/3447
Hispanic 0.084 288/3430 0.104 359/3447
Other 0.035 121/3430 0.056 193/3447
Diagnosis 6877 X23=7.13, P=0.068
Dilated cardiomyopathy, non-ischemic 0.456 1563/3430 0.457 1577/3447
Ischemic cardiomyopathy 0.359 1232/3430 0.346 1191/3447
Restrictive cardiomyopathy 0.107 368/3430 0.102 352/3447
Other 0.078 267/3430 0.095 327/3447
Diabetes 6877 X22=2.66, P=0.264
History of DM 0.291 997/3430 0.274 945/3447
Non-diabetic 0.708 2429/3430 0.724 2496/3447
Unknown 0.001 4/3430 0.002 6/3447
Renal_Function 6877 X24=36.83, P=<0.001
Dialysis 0.032 110/3430 0.031 107/3447
GFR < 30 ml/min/1.73 m^2 0.025 87/3430 0.038 131/3447
GFR >= 30 & <60 ml/min/1.73 m^2 0.361 1238/3430 0.386 1329/3447
GFR >= 60 ml/min/1.73 m^2 0.582 1995/3430 0.540 1860/3447
Unknown 0.000 0/3430 0.006 20/3447
Functional_Status 6877 X23=134.07, P=<0.001
Limited Impairment, 10-30% 0.264 907/3430 0.172 592/3447
Moderate Impairment, 40-60% 0.268 920/3430 0.237 817/3447
Severe Impairment, 70-100% 0.424 1455/3430 0.553 1907/3447
Unknown 0.043 148/3430 0.038 131/3447
Cardiac Index 6458 1.80 2.22 2.69 1.76 2.16 2.64 F1,6456=9.25, P=0.002
Mean Pulmonary Capillary Wedge Pressure 6181 12.0 18.0 25.0 13.0 20.0 26.0 F1,6179=30.51, P=<0.001
Status 1A Justification at Transplant 6877 X25=247.04, P=<0.001
Status 1A - (Exception) 0.072 246/3430 0.087 299/3447
Status 1A - (High dose inotropes) 0.250 858/3430 0.333 1149/3447
Status 1A (MCS complication) 0.369 1266/3430 0.200 690/3447
Status 1A - (Mechanical ventilation) 0.003 12/3430 0.003 12/3447
Status 1A (MCS for shock) 0.305 1045/3430 0.376 1297/3447
Status 1A (no justification listed) 0.001 3/3430 0.000 0/3447
payor 6877 X23=76.76, P=<0.001
Medicaid 0.124 426/3430 0.128 442/3447
Medicare 0.365 1251/3430 0.301 1039/3447
Other 0.055 188/3430 0.028 96/3447
Private 0.456 1565/3430 0.543 1870/3447

For continuous variables, median and IQRs are presented and group comparison testing p-values obtained using Kruskal-Wallis. For categorical variables, number (%) are presented and group comparison testing p-values calculated with Pearson Chi-squared test. GFR = Glomerular Filtration Rate, calculated by the Modification in Diet in Renal Disease (MDRD) formula. Body surface area for cardiac index calculated with method of Du Bois. Functional status is on the Karnofsky scale.

Table S5 – Classification of heart transplant recipients from 2006-2015 based on the new Status 1-6 system.

tangram::rmd(tangram::tangram(data = stat_by_benefit, three_status~ six_status))
N Status 1A Status 1B Status 2 Test Statistic
(N=6877) (N=4708) (N=723)
six_status 12308 X28=15011.30, P=<0.001
Status 1 0.026 176/6877 0.000 0/4708 0.000 0/723
Status 2 0.110 756/6877 0.000 0/4708 0.000 0/723
Status 3 0.567 3899/6877 0.000 0/4708 0.000 0/723
Status 4 0.298 2046/6877 1.000 4708/4708 0.256 185/723
Status 6 0.000 0/6877 0.000 0/4708 0.744 538/723

Classification of recipients from 2006-2015 based on new Status 1-6 system. The majority ( 56%) of Status 1A recipients were coded as Status 3. A substantial portion (31%) of Status 1A candidates would have been downgraded to Status 4 because of violation of the cardiogenic shock requirement. A small number of recipients 288 were assigned a higher status because of restrictive cardiomyopathy

##Figure S4: Association of center transplant volume with wait-list survival, post-transplant survival, and survival benefit from heart transplantation.

to_plot <- five_year_means %>%
  select(num_tx, mean_five_year, mean_five_year_post, mean_five_year_wait) %>%
  gather(key, value, -num_tx) %>%
  mutate( key = case_when(
    key == "mean_five_year" ~ "survival benefit",
    key == "mean_five_year_wait" ~ "waitlist survival",
    key == "mean_five_year_post" ~ "post-transplant survival"
  )
  )

ggplot(to_plot, aes(x = num_tx, y = 100*value, color = key, group = key)) + 
  geom_point( size = 3) + geom_smooth( method = "lm") +
  scale_color_brewer(palette = "Set1", direction = -1 ) +
  labs(y = "Five-year estimate (%)",  
       x = "Number of Transplants performed during study time period", 
       color = "") + 
  ylim(0, 100)

ggsave("Fig_S4.pdf")

Across all centers, transplant volume was weakly associated with post-transplant survival (+0.59; 95% CI, 0.074 to 1.1), however was not associated with either candidate urgency (+0.49; 95% CI, -0.29 to 1.3) or survival benefit (+0.099; 95% CI, -0.56 to 0.75) (Figure S4).

Table S6: Six-status coxme results

print(six_status, digits = 2)
Cox mixed-effects model fit by maximum likelihood
  Data: to_model
  events, n = 11058, 163240
  Iterations= 23 211 
                  NULL Integrated    Fitted
Log-likelihood -107600  -105838.3 -105664.7

                  Chisq  df p  AIC  BIC
Integrated loglik  3523  14 0 3495 3393
 Penalized loglik  3871 125 0 3621 2707

Model:  f_coxme 
Fixed coefficients
               coef exp(coef) se(coef)     z       p
tx           -2.924     0.054    0.139 -21.0 0.0e+00
status_2     -0.869     0.419    0.089  -9.7 0.0e+00
status_3     -1.526     0.217    0.083 -18.3 0.0e+00
status_4     -2.169     0.114    0.079 -27.6 0.0e+00
status_6     -2.614     0.073    0.082 -31.8 0.0e+00
tx_risky_don  0.262     1.300    0.028   9.4 0.0e+00
era_tx       -0.053     0.949    0.030  -1.7 8.3e-02
tx:status_2   0.737     2.090    0.152   4.8 1.3e-06
tx:status_3   1.250     3.489    0.142   8.8 0.0e+00
tx:status_4   1.851     6.368    0.138  13.4 0.0e+00
tx:status_6   2.287     9.841    0.149  15.3 0.0e+00

Random effects
 Group  Variable  Std Dev Variance Corr  
 center Intercept  0.195   0.038   -0.386
        tx         0.212   0.045         

95% Confidence Intervals of coefficients

#write_csv(table_fe_results(six_status), "six_status_fixed.csv")
table_fe_results(six_status)
to_plot <- plot_tx_effects(six_status) %>% 
  mutate(`Patient Status` = factor(covariate, 
                                   levels = c("tx",
                                              "tx:status_2", 
                                              "tx:status_3", 
                                              "tx:status_4", 
                                              "tx:status_6", 
                                              "tx_risky_don","era_tx"), 
                                   labels =  c("Status 1", 
                                               "Status 2", 
                                               "Status 3", 
                                               "Status 4", 
                                               "Status 6", 
                                               "High risk donor (Status 1 recipient)", 
                                               "Before 2010 (Status 1 recipient)")))

ggplot(data = to_plot %>% 
         filter(!(covariate %in% c("tx_risky_don","era_tx"))), 
       aes(y = `Patient Status`, x = haz)) + 
  geom_point() + 
  geom_errorbarh(aes(xmin = low_ci, xmax = up_ci))  + 
  scale_x_continuous(limits = c(0,0.75), breaks = c(0, 0.25, 0.5, 0.75),  
                     name = "Hazard Ratio for death relative to waiting") +
  theme_fivethirtyeight() + 
  theme(axis.title = element_text(), 
        axis.title.y = element_blank(),
        axis.title.x = element_text(vjust = 0.1))

stat_list <- c("status_1", "status_2", "status_3", "status_4", "status_6")

tx_estimates <- tibble(status = stat_list) %>%
  mutate(
    hazard = "",
    low_ci = "", 
    up_ci = ""
  )

i <- 1
for (s in stat_list) {
  
  if (s == "status_1"){
    int <- "tx"
  }
  else{
    int <- paste0("tx:", s)
  }
  
  tx_estimates$hazard[i] <-comma_2(filter(to_plot, covariate == int)$haz)
  
  tx_estimates$low_ci[i] <-comma_2(filter(to_plot, covariate == int)$low_ci)
  
  tx_estimates$up_ci[i] <-comma_2(filter(to_plot, covariate == int)$up_ci)
  
  i <- i + 1
}

ggsave("HR_transplant_six_status.pdf")

Hazard ratios of transplantation by 6-Status Justification at transplantation as estimated by mixed-effects model, adjusted for donor risk, ischemic time, and year of transplant (see supplement for full model results).

Hazard ratios of transplantation conditional Status at transplantation as estimated by mixed-effects model (see supplement for full model results). Status 1 candidates had hazard ratio of transplant of 0.054 (95% CI 0.041-0.071). Compared to this group, Status 2-6 candidates had significantly lower benefit from heart transplanation.

Status 2 had a hazard ratio of 0.11 (95% CI 0.096-0.13), Status 3 0.19 (95% CI 0.17-0.21), Status 4 0.34 (95% CI 0.32-0.37), and Status 6 0.53 (95% CI 0.46-0.61)

Sensitivity analyses

Fixed effects sensitivity analysis

Here we fit the model

\(h(t) = h_0(t)exp(center + status + tx*(center + status + donrisk + txYear)\)

num_tx_by_center <- to_model %>%
  filter(dead ==1) %>%
  group_by(center) %>%
  count()

#center 602 is close to the "mean" center
for_fe <- to_model %>%
  left_join(num_tx_by_center, by = "center") %>%
  filter(n>20) %>%
  mutate(three_status = factor(three_status),
         center = factor(center),
         center = relevel(center, ref = "602"))
  
full_fe <- "Surv(t_1, t_2, dead) ~ tx*(three_status + center) + tx_risky_don + era_tx"

full_fe_model <- coxph(as.formula(full_fe), for_fe)

centers_exlcuded <-  length(unique(to_model$center)) - length(levels(for_fe$center))

This model treats center as a fixed effect. To get this model to converge, we excluded 9 centers with less than 20 deaths (before or after transplant)

print(full_fe_model, digits = 2)
Call:
coxph(formula = as.formula(full_fe), data = for_fe)

                            coef exp(coef) se(coef)     z      p
tx                       -1.7846    0.1679   0.2160  -8.3 <2e-16
three_statusStatus 1B    -0.9490    0.3871   0.0320 -29.6 <2e-16
three_statusStatus 2     -1.3824    0.2510   0.0371 -37.3 <2e-16
center7                  -0.0589    0.9428   0.1853  -0.3  0.751
center8                  -0.4979    0.6078   0.2253  -2.2  0.027
center18                 -0.4205    0.6567   0.2099  -2.0  0.045
center25                 -0.1087    0.8970   0.2166  -0.5  0.616
center33                 -0.2485    0.7800   0.1753  -1.4  0.156
center47                  0.1439    1.1548   0.2626   0.5  0.584
center55                  0.4539    1.5745   0.2510   1.8  0.071
center63                 -0.2472    0.7810   0.2720  -0.9  0.363
center64                  0.1690    1.1841   0.2253   0.8  0.453
center65                 -0.4987    0.6073   0.2625  -1.9  0.057
center67                 -0.1665    0.8466   0.2125  -0.8  0.433
center72                  0.0993    1.1044   0.1916   0.5  0.604
center78                 -0.0439    0.9570   0.1759  -0.2  0.803
center79                 -0.1057    0.8997   0.2104  -0.5  0.616
center91                 -0.1695    0.8441   0.2152  -0.8  0.431
center94                 -0.6451    0.5246   0.2511  -2.6  0.010
center96                 -0.2542    0.7755   0.2185  -1.2  0.245
center108                -0.2163    0.8055   0.1856  -1.2  0.244
center119                -0.0430    0.9580   0.1894  -0.2  0.821
center128                -0.5579    0.5724   0.2086  -2.7  0.007
center131                -0.4926    0.6110   0.1951  -2.5  0.012
center136                -0.3042    0.7377   0.1843  -1.7  0.099
center141                -0.0155    0.9846   0.1747  -0.1  0.929
center147                -0.1943    0.8234   0.2512  -0.8  0.439
center149                -0.2963    0.7435   0.2719  -1.1  0.276
center165                -0.4731    0.6230   0.2389  -2.0  0.048
center171                -0.7144    0.4895   0.2201  -3.2  0.001
center178                -0.5852    0.5570   0.2024  -2.9  0.004
center183                -0.3760    0.6866   0.2066  -1.8  0.069
center185                 0.2324    1.2616   0.2446   1.0  0.342
center190                 0.0522    1.0535   0.1979   0.3  0.792
center195                -0.1341    0.8745   0.2339  -0.6  0.566
center199                -0.1887    0.8281   0.2719  -0.7  0.488
center201                 0.0038    1.0038   0.1958   0.0  0.984
center210                -0.0412    0.9596   0.1832  -0.2  0.822
center213                -0.5390    0.5833   0.2672  -2.0  0.044
center221                 0.0137    1.0138   0.1739   0.1  0.937
center234                 0.4450    1.5605   0.3046   1.5  0.144
center298                 0.0989    1.1040   0.1815   0.5  0.586
center301                -0.5336    0.5865   0.1779  -3.0  0.003
center303                -0.4471    0.6395   0.1910  -2.3  0.019
center307                -0.3072    0.7355   0.1979  -1.6  0.121
center313                 0.3507    1.4201   0.1843   1.9  0.057
center324                -0.3478    0.7062   0.2170  -1.6  0.109
center337                -0.2016    0.8175   0.1760  -1.1  0.252
center338                -0.2270    0.7969   0.2416  -0.9  0.347
center348                -0.1250    0.8825   0.1739  -0.7  0.472
center350                -0.4058    0.6664   0.1812  -2.2  0.025
center351                 0.0669    1.0692   0.1679   0.4  0.690
center359                -0.7082    0.4925   0.2445  -2.9  0.004
center372                 0.2889    1.3349   0.2183   1.3  0.186
center377                -0.6394    0.5276   0.3134  -2.0  0.041
center380                -0.2149    0.8066   0.2219  -1.0  0.333
center382                -0.0611    0.9407   0.1735  -0.4  0.725
center388                -0.0876    0.9162   0.2124  -0.4  0.680
center402                -0.7369    0.4786   0.2477  -3.0  0.003
center404                -0.1221    0.8851   0.1953  -0.6  0.532
center408                -0.4545    0.6348   0.2586  -1.8  0.079
center434                -0.3670    0.6928   0.1617  -2.3  0.023
center442                -0.2675    0.7653   0.1798  -1.5  0.137
center445                -0.3730    0.6887   0.2168  -1.7  0.085
center446                -0.4926    0.6110   0.1966  -2.5  0.012
center459                -0.1680    0.8453   0.2256  -0.7  0.456
center465                -0.2128    0.8083   0.1679  -1.3  0.205
center479                -0.2484    0.7800   0.2233  -1.1  0.266
center484                 0.6843    1.9823   0.3235   2.1  0.034
center486                -0.4359    0.6467   0.2719  -1.6  0.109
center487                -0.0086    0.9915   0.1928   0.0  0.965
center507                -0.5512    0.5763   0.2416  -2.3  0.023
center512                -0.2676    0.7652   0.1979  -1.4  0.176
center520                -0.4155    0.6600   0.2125  -2.0  0.051
center523                -0.0094    0.9906   0.2479   0.0  0.970
center527                -0.0829    0.9204   0.1848  -0.4  0.654
center532                -0.1198    0.8871   0.2115  -0.6  0.571
center534                 0.1572    1.1702   0.2389   0.7  0.511
center536                -0.3083    0.7347   0.1904  -1.6  0.105
center588                 0.9604    2.6128   0.3354   2.9  0.004
center595                 0.0278    1.0282   0.2314   0.1  0.904
center615                 0.1760    1.1924   0.2417   0.7  0.466
center620                -0.0371    0.9636   0.1697  -0.2  0.827
center633                 0.0690    1.0715   0.2075   0.3  0.739
center640                -0.4037    0.6679   0.1864  -2.2  0.030
center642                -0.5537    0.5748   0.2389  -2.3  0.020
center643                -0.1007    0.9042   0.1613  -0.6  0.532
center645                 0.1723    1.1881   0.2076   0.8  0.406
center648                -0.1526    0.8584   0.2968  -0.5  0.607
center656                 0.4038    1.4975   0.1736   2.3  0.020
center667                -0.3170    0.7283   0.2075  -1.5  0.127
center670                -0.0583    0.9434   0.3351  -0.2  0.862
center675                 0.0308    1.0313   0.1897   0.2  0.871
center688                -0.6747    0.5093   0.2831  -2.4  0.017
center690                -0.5054    0.6032   0.2510  -2.0  0.044
center696                -0.4899    0.6127   0.1945  -2.5  0.012
center700                -0.3198    0.7263   0.1997  -1.6  0.109
center701                -0.6389    0.5279   0.2511  -2.5  0.011
center703                -0.6902    0.5015   0.2115  -3.3  0.001
center708                -0.1915    0.8257   0.2182  -0.9  0.380
center733                -0.1575    0.8543   0.2201  -0.7  0.474
center736                -0.3169    0.7284   0.1916  -1.7  0.098
center742                -0.0582    0.9434   0.2968  -0.2  0.844
center746                 0.0610    1.0629   0.1794   0.3  0.734
center749                -0.3705    0.6904   0.2182  -1.7  0.090
center838                -0.5825    0.5585   0.2833  -2.1  0.040
tx_risky_don              0.2629    1.3007   0.0283   9.3 <2e-16
era_tx                   -0.0522    0.9491   0.0309  -1.7  0.091
tx:three_statusStatus 1B  0.9199    2.5091   0.0445  20.7 <2e-16
tx:three_statusStatus 2   1.3475    3.8477   0.0654  20.6 <2e-16
tx:center7               -0.3549    0.7013   0.2816  -1.3  0.208
tx:center8                0.2563    1.2921   0.3187   0.8  0.421
tx:center18              -0.3720    0.6894   0.3049  -1.2  0.222
tx:center25               0.1620    1.1759   0.2992   0.5  0.588
tx:center33              -0.1296    0.8784   0.2467  -0.5  0.599
tx:center47              -0.4173    0.6588   0.3519  -1.2  0.236
tx:center55              -0.4569    0.6332   0.3531  -1.3  0.196
tx:center63              -0.0981    0.9065   0.4012  -0.2  0.807
tx:center64              -0.5621    0.5700   0.3187  -1.8  0.078
tx:center65               0.2659    1.3046   0.3699   0.7  0.472
tx:center67              -0.6446    0.5249   0.3364  -1.9  0.055
tx:center72              -0.5607    0.5708   0.2645  -2.1  0.034
tx:center78              -0.2863    0.7511   0.2485  -1.2  0.249
tx:center79              -0.5211    0.5939   0.3015  -1.7  0.084
tx:center91              -0.2808    0.7552   0.3045  -0.9  0.357
tx:center94               0.1371    1.1469   0.3446   0.4  0.691
tx:center96              -0.0965    0.9080   0.3266  -0.3  0.768
tx:center108              0.1990    1.2202   0.2972   0.7  0.503
tx:center119             -0.5896    0.5545   0.2824  -2.1  0.037
tx:center128              0.0203    1.0205   0.2929   0.1  0.945
tx:center131              0.1267    1.1351   0.2632   0.5  0.630
tx:center136              0.1143    1.1211   0.2663   0.4  0.668
tx:center141             -0.3803    0.6837   0.2643  -1.4  0.150
tx:center147              0.6130    1.8460   0.4227   1.5  0.147
tx:center149              0.2429    1.2749   0.3588   0.7  0.498
tx:center165             -0.4788    0.6195   0.3702  -1.3  0.196
tx:center171              0.8076    2.2424   0.3213   2.5  0.012
tx:center178             -0.0620    0.9399   0.3007  -0.2  0.837
tx:center183             -0.0253    0.9750   0.2864  -0.1  0.930
tx:center185             -0.6063    0.5453   0.3834  -1.6  0.114
tx:center190             -0.1894    0.8274   0.2774  -0.7  0.495
tx:center195             -0.2354    0.7903   0.3236  -0.7  0.467
tx:center199              0.1528    1.1651   0.3614   0.4  0.672
tx:center201             -0.1768    0.8379   0.2829  -0.6  0.532
tx:center210             -0.0543    0.9472   0.2833  -0.2  0.848
tx:center213              0.1505    1.1624   0.3610   0.4  0.677
tx:center221             -0.5454    0.5796   0.2726  -2.0  0.045
tx:center234             -0.7152    0.4891   0.4663  -1.5  0.125
tx:center298             -0.5603    0.5710   0.2822  -2.0  0.047
tx:center301             -0.2225    0.8005   0.2836  -0.8  0.433
tx:center303             -0.1274    0.8804   0.2875  -0.4  0.658
tx:center307             -0.2421    0.7850   0.3096  -0.8  0.434
tx:center313             -0.5680    0.5667   0.2747  -2.1  0.039
tx:center324             -0.0380    0.9628   0.3177  -0.1  0.905
tx:center337             -0.4626    0.6296   0.2652  -1.7  0.081
tx:center338             -0.7673    0.4643   0.3866  -2.0  0.047
tx:center348             -0.6200    0.5379   0.2823  -2.2  0.028
tx:center350             -0.2140    0.8074   0.2737  -0.8  0.434
tx:center351             -0.4278    0.6519   0.2545  -1.7  0.093
tx:center359              0.1574    1.1705   0.3073   0.5  0.608
tx:center372             -0.4777    0.6202   0.3251  -1.5  0.142
tx:center377             -0.1259    0.8817   0.4304  -0.3  0.770
tx:center380             -0.6783    0.5075   0.3167  -2.1  0.032
tx:center382             -0.0853    0.9183   0.2455  -0.3  0.728
tx:center388             -0.1189    0.8879   0.3119  -0.4  0.703
tx:center402              0.2823    1.3262   0.3266   0.9  0.387
tx:center404             -0.3452    0.7081   0.2658  -1.3  0.194
tx:center408              0.1537    1.1661   0.3451   0.4  0.656
tx:center434             -0.1631    0.8495   0.2387  -0.7  0.494
tx:center442             -0.5739    0.5633   0.3111  -1.8  0.065
tx:center445             -0.4197    0.6573   0.3190  -1.3  0.188
tx:center446              0.6026    1.8269   0.2761   2.2  0.029
tx:center459             -0.1079    0.8978   0.3199  -0.3  0.736
tx:center465             -0.4640    0.6288   0.2468  -1.9  0.060
tx:center479             -0.2044    0.8151   0.3142  -0.7  0.515
tx:center484             -0.6068    0.5451   0.4789  -1.3  0.205
tx:center486              0.7214    2.0573   0.4187   1.7  0.085
tx:center487             -0.1023    0.9027   0.2896  -0.4  0.724
tx:center507             -0.2883    0.7495   0.3294  -0.9  0.382
tx:center512             -0.1300    0.8781   0.2867  -0.5  0.650
tx:center520              0.4900    1.6323   0.2969   1.7  0.099
tx:center523             -0.1633    0.8493   0.3528  -0.5  0.643
tx:center527             -0.2133    0.8079   0.2573  -0.8  0.407
tx:center532              0.0027    1.0027   0.3025   0.0  0.993
tx:center534             -0.3708    0.6902   0.3536  -1.0  0.294
tx:center536             -0.1718    0.8421   0.2602  -0.7  0.509
tx:center588             -1.4317    0.2389   0.4340  -3.3  0.001
tx:center595             -0.6684    0.5125   0.3324  -2.0  0.044
tx:center615             -0.1448    0.8652   0.3329  -0.4  0.663
tx:center620             -0.4204    0.6568   0.2646  -1.6  0.112
tx:center633              0.1392    1.1494   0.2922   0.5  0.634
tx:center640             -0.2954    0.7442   0.2831  -1.0  0.297
tx:center642              0.2081    1.2313   0.3538   0.6  0.556
tx:center643             -0.0308    0.9696   0.2424  -0.1  0.899
tx:center645             -0.5774    0.5614   0.3015  -1.9  0.056
tx:center648              0.4840    1.6225   0.3834   1.3  0.207
tx:center656             -0.6646    0.5145   0.2616  -2.5  0.011
tx:center667             -0.0556    0.9459   0.2921  -0.2  0.849
tx:center670             -0.2930    0.7460   0.4865  -0.6  0.547
tx:center675             -0.2036    0.8158   0.2638  -0.8  0.440
 [ reached getOption("max.print") -- omitted 13 rows ]

Likelihood ratio test=3849  on 213 df, p=<2e-16
n= 162054, number of events= 10962 
sum_fe_model <- summary(full_fe_model)$coefficients

tx_1a <- sum_fe_model[1,1]
  
fe_coef <- tibble(name = names(full_fe_model$coefficients), 
                  beta = unname(sum_fe_model[,1])) %>%
  filter(grepl( "center",name)== TRUE) %>%
  mutate(tx = ifelse(grepl( "tx:",name), "transplant", "waitlist"),
         center = numextract(name)) %>%
  select(-name) %>%
  spread(tx, beta)
  
vcov_full_fe <- vcov(full_fe_model)

tx_wait_cov <- vector("double", length = length(unique(for_fe$center)))
center_ids <- vector("double", length = length(unique(for_fe$center)))
wait_variance <- vector("double", length = length(unique(for_fe$center)))
tx_variance <- vector("double", length = length(unique(for_fe$center)))
i <- 1
j <- 1
for (n in names(vcov_full_fe[,1])){
  if (grepl("center", n) == TRUE & grepl("tx", n) == FALSE){
    tx_effect <- paste0("tx:",n)
    tx_wait_cov[[i]] <- vcov_full_fe[[tx_effect,n]]
    
    wait_variance[[i]] <- vcov_full_fe[[n,n]]
    center_ids[[i]] <- numextract(n)
    i <- i + 1
  }
  if (grepl("tx:center", n) == TRUE){
    tx_variance[[j]] <- vcov_full_fe[[n, n]]
    j <- j + 1
  }
}

tx_wait_cov <- tibble(center = center_ids, 
                      wait_variance = wait_variance, 
                      tx_variance = tx_variance, 
                      covariance = tx_wait_cov)


fe_coef <- fe_coef %>%
  left_join(tx_wait_cov) %>%
  mutate(tx_benefit =  transplant - waitlist) %>%
  arrange(-tx_benefit) %>%
  mutate(id = row_number())
Joining, by = "center"

Histogram of center relative survival benefits

ggplot(fe_coef, aes(x = tx_benefit)) + geom_histogram(breaks = seq(-3, 2, 0.25))
  labs(x = "center effect on benefit of transplant\n(log hazard ratio of transplant (Status 1A)", y = "number of centers") +
  theme_few()
NULL
ggsave("eFigure6.pdf")


s_w_norm_test <- comma_2(shapiro.test(fe_coef$tx_benefit)[[2]])

Distribution of center-specific survival benefits for a Status 1A recipient, calculated by subtracting the log hazard of waitlist from the the log hazard of transplant at the center. The shapiro-wilk test for non-normality was not significant (p = 0.18). The variance of the survival benefit of transplant was 0.378 on log hazard ratio scale, -135% lower than the three-status model.

\(benefit = \beta_{tx, i} - \beta_{wait, i}\)

Relationship between fixed-effect and random-effect center estimates of survival benefit from heart transplantation.


for_spear <- center_re %>%
  filter(center %in% fe_coef$center) %>%
  left_join(fe_coef %>% select(center, tx_benefit))

spearman_cor <- cor(for_spear$benefit, for_spear$tx_benefit,method = "spearman")

ggplot(for_spear, aes(x = benefit, y = tx_benefit)) + geom_point() +
  labs( x = "benefit of transplant (RE estimate) log hazard", 
        y = "benefit of transplant (FE estimate) log hazard")

ggsave("eFig7.pdf")

Scatter plot of center fixed-effect (y-axis) and random-effect (x-axis) estimates of the survival benefit of heart transplantation (on log hazard scale). A spearman correlation between the two was -0.9696986

Association of center waitlist risk with survival benefit from transplantation


ggplot(fe_coef, aes(x = waitlist, y = tx_benefit)) + geom_point(size = 2.5, alpha = 0.9) +
  labs(x = "Waitlist relative risk (log hazard)", 
       y = "Relative benefit of transplant (log hazard)") +
  geom_line(aes(linetype = "Mean Center"), 
            y = 0, color = "black") + 
  scale_linetype_manual(values = "dashed") 


slope_fe <- lm(tx_benefit ~ waitlist, data = fe_coef)

slope_pct_fe <- comma_2(slope_fe$coefficients[[2]])

ci_slope_fe_wait_low <- comma_2(10*-confint(slope_fe, 'waitlist', level=0.95)[1,1])

ci_slope_fe_wait_up <- comma_2(10*-confint(slope_fe, 'waitlist', level=0.95)[1,2])

ggsave("eFigure8.pdf")

The association between estimated log hazard of death on waitlist at a given center (x-axis) and log hazard survival benefit (y-axis). A linear association is observed, for every one unit increase in the log hazard of waitlist risk the log hazard of transplant decreased -1.8 (95% CI 19 - 16).

Alternative ME models

to_model <- read.csv("clean_time_series_revise2006_2015.csv") %>%
  mutate(
    ischemia = case_when(
            REC_HR_ISCH/60 < 2 ~ 1,
            REC_HR_ISCH/60 >= 2 & REC_HR_ISCH/60 < 4 ~ 2,
            REC_HR_ISCH/60 >=4 & REC_HR_ISCH/60 < 6 ~ 3,
            REC_HR_ISCH/60 >= 6 & REC_HR_ISCH/60 < 8 ~4,
            TRUE ~ 5
    ),
don_age = factor(case_when(
            DON_AGE >=40 & DON_AGE <50 ~ "30-50",
            DON_AGE >= 50 ~ "> 50",
            TRUE ~ "< 30"
        )),
don_renal_function = 
        case_when(
            (DON_BUN/DON_CREAT) > 30 ~ 1,
            TRUE ~ 0
        ),
race_mismatch = 
        case_when(
            black != black_don ~ 1,
            TRUE ~ 0
        )
    )

ME sensitivity analyses

  1. better_donor_year <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(list_year)) + don_renal_function + don_age + race_mismatch + ischemia"

  2. six-status, donor quality and transplant year better_donor_year_candidate <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(list_year) + age + female + bmi_low + bmi_high + simple_diag + cross_match +blood_type) + don_renal_function + don_age + race_mismatch + ischemia"

  3. three status, region & LVAD region_lvad <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(REGION) + cf_lvad) + tx_risky_don + era_tx"

#three-status, donor quality, and transplant year
better_donor_year <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(list_year)) + don_renal_function + don_age + race_mismatch + ischemia"


#six-status, donor quality and transplant year
better_donor_year_candidate <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(list_year) + age + female + bmi_low + bmi_high + simple_diag + cross_match +blood_type) + don_renal_function + don_age + race_mismatch + ischemia"


#three status, region & LVAD
region_lvad <- "Surv(t_1, t_2, dead) ~ tx*(stat_2 + stat_1b + factor(REGION) + cf_lvad) + tx_risky_don + era_tx"
me_models_alt <-  vector(mode = "list", length(formulas_alt))

for (i in seq_along(formulas_alt)) {
  f_coxme <- as.formula(paste(formulas_alt[[i]], " + (1+ tx|center)"))
  start_time <- Sys.time()
  fit <- coxme(f_coxme, data = to_model)
  me_models_alt[[i]] <- fit
  end_time <- Sys.time()
  diff_time <- end_time - start_time
  print(f_coxme)
  print(diff_time)
}

save.image("end_results_with_alts.RData")

Expanded donor factors

print(me_models_alt[[1]])
Cox mixed-effects model fit by maximum likelihood
  Data: alt_to_model
  events, n = 11052, 163109
  Iterations= 24 148 
                    NULL Integrated    Fitted
Log-likelihood -107534.9    -105726 -105540.2

                    Chisq     df p     AIC     BIC
Integrated loglik 3617.96  31.00 0 3555.96 3329.34
 Penalized loglik 3989.47 144.03 0 3701.42 2648.55

Model:  f_coxme 
Fixed coefficients
                                coef  exp(coef)   se(coef)      z       p
tx                       -2.40330252 0.09041885 0.07950817 -30.23 0.0e+00
stat_2                   -1.43060646 0.23916383 0.03726867 -38.39 0.0e+00
stat_1b                  -0.94614340 0.38823541 0.03166912 -29.88 0.0e+00
factor(list_year)2007    -0.03922706 0.96153236 0.06562071  -0.60 5.5e-01
factor(list_year)2008    -0.10269913 0.90239844 0.06336356  -1.62 1.1e-01
factor(list_year)2009    -0.15341267 0.85777567 0.06214082  -2.47 1.4e-02
factor(list_year)2010    -0.23099307 0.79374497 0.06254102  -3.69 2.2e-04
factor(list_year)2011    -0.31173899 0.73217260 0.06496752  -4.80 1.6e-06
factor(list_year)2012    -0.30452275 0.73747525 0.06386275  -4.77 1.9e-06
factor(list_year)2013    -0.40327413 0.66812892 0.06384416  -6.32 2.7e-10
factor(list_year)2014    -0.33509032 0.71527348 0.06241014  -5.37 7.9e-08
factor(list_year)2015    -0.48253235 0.61721840 0.06590417  -7.32 2.4e-13
don_renal_function       -0.03362085 0.96693805 0.02783947  -1.21 2.3e-01
don_age> 50               0.38436954 1.46868808 0.04551777   8.44 0.0e+00
don_age30-50              0.20195758 1.22379609 0.03462113   5.83 5.4e-09
race_mismatch             0.17018309 1.18552189 0.03017527   5.64 1.7e-08
ischemia                  0.14592292 1.15710699 0.02361290   6.18 6.4e-10
tx:stat_2                 1.40497859 4.07543950 0.06474647  21.70 0.0e+00
tx:stat_1b                0.91921382 2.50731840 0.04384848  20.96 0.0e+00
tx:factor(list_year)2007 -0.03132753 0.96915809 0.08357561  -0.37 7.1e-01
tx:factor(list_year)2008  0.05827196 1.06000323 0.08281571   0.70 4.8e-01
tx:factor(list_year)2009  0.11930700 1.12671577 0.08298896   1.44 1.5e-01
tx:factor(list_year)2010  0.11326307 1.11992651 0.08522732   1.33 1.8e-01
tx:factor(list_year)2011  0.25650368 1.29240352 0.08865318   2.89 3.8e-03
tx:factor(list_year)2012  0.23540186 1.26541719 0.08958282   2.63 8.6e-03
tx:factor(list_year)2013  0.45418073 1.57488260 0.09051088   5.02 5.2e-07
tx:factor(list_year)2014  0.44445880 1.55964589 0.09224301   4.82 1.4e-06
tx:factor(list_year)2015  0.70528065 2.02441477 0.09787104   7.21 5.8e-13

Random effects
 Group  Variable  Std Dev     Variance    Corr       
 center Intercept  0.21296954  0.04535602 -0.48052397
        tx         0.23821986  0.05674870            
write_csv(table_fe_results(me_models_alt[[1]]), "expanded_donor_time.csv")

three_stat_don_year <- variance_survival_benefit(me_models_alt[[1]])

The variance of the survival benefit of transplant was 0.151 on log hazard ratio scale, 6.3% lower than the three-status model.

Expanded donor factors and candidate variables


print(me_models_alt[[2]], digits = 2)
Cox mixed-effects model fit by maximum likelihood
  Data: alt_to_model
  events, n = 11052, 163109
  Iterations= 20 124 
                    NULL Integrated    Fitted
Log-likelihood -107534.9  -105459.5 -105275.3

                  Chisq  df p  AIC  BIC
Integrated loglik  4151  53 0 4045 3657
 Penalized loglik  4519 165 0 4189 2979

Model:  f_coxme 
Fixed coefficients
                                             coef exp(coef) se(coef)      z       p
tx                                       -1.49188      0.22   0.1260 -11.84 0.0e+00
stat_2                                   -1.45977      0.23   0.0377 -38.72 0.0e+00
stat_1b                                  -0.93946      0.39   0.0318 -29.57 0.0e+00
factor(list_year)2007                    -0.03458      0.97   0.0658  -0.53 6.0e-01
factor(list_year)2008                    -0.08925      0.91   0.0636  -1.40 1.6e-01
factor(list_year)2009                    -0.13473      0.87   0.0624  -2.16 3.1e-02
factor(list_year)2010                    -0.22585      0.80   0.0628  -3.59 3.2e-04
factor(list_year)2011                    -0.29964      0.74   0.0653  -4.59 4.5e-06
factor(list_year)2012                    -0.28734      0.75   0.0643  -4.47 7.9e-06
factor(list_year)2013                    -0.37461      0.69   0.0644  -5.82 5.9e-09
factor(list_year)2014                    -0.28896      0.75   0.0632  -4.57 4.8e-06
factor(list_year)2015                    -0.45012      0.64   0.0666  -6.76 1.3e-11
age                                       0.01486      1.01   0.0012  11.94 0.0e+00
female                                    0.01608      1.02   0.0328   0.49 6.2e-01
bmi_low                                   0.06362      1.07   0.0360   1.77 7.7e-02
bmi_high                                  0.05618      1.06   0.0319   1.76 7.8e-02
simple_diagIschemic cardiomyopathy        0.13350      1.14   0.0328   4.07 4.7e-05
simple_diagOther                          0.53039      1.70   0.0425  12.48 0.0e+00
simple_diagRestrictive cardiomyopathy     0.19077      1.21   0.0519   3.68 2.3e-04
cross_match                               0.39633      1.49   0.0350  11.34 0.0e+00
blood_typeAB                              0.13814      1.15   0.0834   1.66 9.7e-02
blood_typeB                              -0.00089      1.00   0.0461  -0.02 9.8e-01
blood_typeO                               0.00624      1.01   0.0300   0.21 8.4e-01
don_renal_function                       -0.01947      0.98   0.0281  -0.69 4.9e-01
don_age> 50                               0.37988      1.46   0.0459   8.27 1.1e-16
don_age30-50                              0.19370      1.21   0.0348   5.57 2.5e-08
race_mismatch                             0.18680      1.21   0.0307   6.08 1.2e-09
ischemia                                  0.13947      1.15   0.0236   5.90 3.6e-09
tx:stat_2                                 1.43691      4.21   0.0665  21.62 0.0e+00
tx:stat_1b                                0.91166      2.49   0.0441  20.66 0.0e+00
tx:factor(list_year)2007                 -0.03424      0.97   0.0837  -0.41 6.8e-01
tx:factor(list_year)2008                  0.04992      1.05   0.0830   0.60 5.5e-01
tx:factor(list_year)2009                  0.10972      1.12   0.0832   1.32 1.9e-01
tx:factor(list_year)2010                  0.11815      1.13   0.0855   1.38 1.7e-01
tx:factor(list_year)2011                  0.25129      1.29   0.0890   2.82 4.8e-03
tx:factor(list_year)2012                  0.23022      1.26   0.0900   2.56 1.1e-02
tx:factor(list_year)2013                  0.43592      1.55   0.0911   4.78 1.7e-06
tx:factor(list_year)2014                  0.41142      1.51   0.0930   4.42 9.7e-06
tx:factor(list_year)2015                  0.69276      2.00   0.0986   7.03 2.1e-12
tx:age                                   -0.01629      0.98   0.0018  -9.25 0.0e+00
tx:female                                 0.00115      1.00   0.0467   0.02 9.8e-01
tx:bmi_low                               -0.12500      0.88   0.0498  -2.51 1.2e-02
tx:bmi_high                               0.12326      1.13   0.0474   2.60 9.4e-03
tx:simple_diagIschemic cardiomyopathy     0.11725      1.12   0.0464   2.53 1.2e-02
tx:simple_diagOther                      -0.37577      0.69   0.0661  -5.69 1.3e-08
tx:simple_diagRestrictive cardiomyopathy -0.10533      0.90   0.0753  -1.40 1.6e-01
tx:cross_match                           -0.29432      0.75   0.0585  -5.03 4.9e-07
tx:blood_typeAB                          -0.13313      0.88   0.1043  -1.28 2.0e-01
tx:blood_typeB                            0.06121      1.06   0.0620   0.99 3.2e-01
tx:blood_typeO                            0.08479      1.09   0.0432   1.96 5.0e-02

Random effects
 Group  Variable  Std Dev Variance Corr  
 center Intercept  0.220   0.048   -0.462
        tx         0.222   0.049         
write_csv(table_fe_results(me_models_alt[[2]]), "expanded_donor_time_can_factors.csv")

three_stat_don_year_can <- variance_survival_benefit(me_models_alt[[2]])

The variance of the survival benefit of transplant was 0.143 on log hazard ratio scale, 11% lower than the three-status model.

BTT LVAD and UNOS Region

print(me_models_alt[[3]])
Cox mixed-effects model fit by maximum likelihood
  Data: alt_to_model
  events, n = 11052, 163109
  Iterations= 38 232 
                    NULL Integrated    Fitted
Log-likelihood -107534.9  -105678.7 -105520.1

                    Chisq     df p     AIC     BIC
Integrated loglik 3712.48  32.00 0 3648.48 3414.55
 Penalized loglik 4029.76 107.21 0 3815.33 3031.56

Model:  f_coxme 
Fixed coefficients
                            coef  exp(coef)   se(coef)      z     p
tx                  -2.357509614 0.09465566 0.13545664 -17.40 0.000
stat_2              -1.570915146 0.20785488 0.03891259 -40.37 0.000
stat_1b             -0.914340893 0.40078070 0.03180455 -28.75 0.000
factor(REGION)2      0.162890733 1.17690809 0.12791626   1.27 0.200
factor(REGION)3      0.102456977 1.10788964 0.12903336   0.79 0.430
factor(REGION)4      0.241820296 1.27356531 0.13127578   1.84 0.065
factor(REGION)5      0.137378133 1.14726188 0.12920832   1.06 0.290
factor(REGION)6      0.110138494 1.11643268 0.17952348   0.61 0.540
factor(REGION)7      0.104057882 1.10966468 0.13217237   0.79 0.430
factor(REGION)8      0.008497164 1.00853337 0.15438771   0.06 0.960
factor(REGION)9      0.033757128 1.03433337 0.15114072   0.22 0.820
factor(REGION)10     0.150832619 1.16280201 0.13754055   1.10 0.270
factor(REGION)11     0.132840629 1.14206797 0.12817764   1.04 0.300
cf_lvad             -0.484829417 0.61580223 0.03251422 -14.91 0.000
tx_risky_don         0.264771016 1.30313255 0.02803009   9.45 0.000
era_tx              -0.025422473 0.97489796 0.03067013  -0.83 0.410
tx:stat_2            1.632155649 5.11488875 0.06669965  24.47 0.000
tx:stat_1b           0.913485484 2.49299671 0.04427438  20.63 0.000
tx:factor(REGION)2   0.086131081 1.08994919 0.15135504   0.57 0.570
tx:factor(REGION)3   0.126922422 1.13532894 0.15340251   0.83 0.410
tx:factor(REGION)4   0.117464298 1.12464148 0.15528196   0.76 0.450
tx:factor(REGION)5  -0.012114629 0.98795846 0.15270754  -0.08 0.940
tx:factor(REGION)6  -0.515973433 0.59691925 0.21897002  -2.36 0.018
tx:factor(REGION)7  -0.016365998 0.98376720 0.15760212  -0.10 0.920
tx:factor(REGION)8   0.069539339 1.07201423 0.18036698   0.39 0.700
tx:factor(REGION)9   0.071850262 1.07449444 0.17778277   0.40 0.690
tx:factor(REGION)10  0.013153071 1.01323995 0.16333119   0.08 0.940
tx:factor(REGION)11  0.073577763 1.07635223 0.15236926   0.48 0.630
tx:cf_lvad           0.677786619 1.96951362 0.04494613  15.08 0.000

Random effects
 Group  Variable  Std Dev     Variance    Corr       
 center Intercept  0.19761376  0.03905120 -0.55829070
        tx         0.19753476  0.03901998            
write_csv(table_fe_results(me_models_alt[[3]]), "btt_lvad_and_region.csv")

btt_lvad_region <- variance_survival_benefit(me_models_alt[[3]])

The variance of the survival benefit of transplant in the model including UNOS region and LVAD was 0.122 on log hazard ratio scale, 24% lower than the three-status model.

LS0tCnRpdGxlOiBNb2RlbCBGaXR0aW5nIGFuZCBBbmFseXNpcyBmb3IgIkFzc29jaWF0aW9uIG9mIHRyYW5zcGxhbnQgY2VudGVyIHdpdGggc3Vydml2YWwgYmVuZWZpdCBhbW9uZyBhZHVsdHMgdW5kZXJnb2luZyBoZWFydCB0cmFuc3BsYW50YXRpb24gaW4gdGhlIFVuaXRlZCBTdGF0ZXMiCmF1dGhvcjogV2lsbGlhbSBGLiBQYXJrZXIgTUQsIE1TLCBBbGxlbiBTLiBBbmRlcnNvbiBNRCwgUm9iZXJ0IEQuIEdpYmJvbnMgUGhELCBFZHdhcmQKICBSIEdhcnJpdHkgSnIgTUQsIExhaW5pZSBGIFJvc3MsIEVsYmVydCBTLiBIdWFuZyBNRCwgYW5kIE1hdHRoZXcgTS4gQ2h1cnBlayBNRCwgUGhECmRhdGU6IDEwLzEvMjAxOQpvdXRwdXQ6CiAgcGRmX2RvY3VtZW50OgogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGpvdXJuYWwKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFLCBjYWNoZSA9IEZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgbGluZXdpZHRoPTYwKQpgYGAKClxwYWdlYnJlYWsgCgpgYGB7ciBwYWNrYWdlcywgIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPSBGQUxTRSwgY2FjaGUgPSBGQUxTRX0KbGlicmFyeShsbWU0KQoKbGlicmFyeShrbml0cikKbGlicmFyeShzdXJ2aXZhbCkKbGlicmFyeShjb3htZSkKCgpsaWJyYXJ5KHpvbykKCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoZ3JpZCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZ2diZWVzd2FybSkKCmxpYnJhcnkoc3RyaW5ncikKCmxpYnJhcnkodGlkeXZlcnNlKQoKbGlicmFyeShwYXJhbGxlbCkKYGBgCgpgYGB7ciBmdW5jdGlvbnN9CiNDb252ZW5pZW5jZSBmdW5jdGlvbnMgCm51bWV4dHJhY3QgPC0gZnVuY3Rpb24oc3RyaW5nKXsKICBhcy5udW1lcmljKHN0cl9leHRyYWN0KHN0cmluZywgIlxcLSpcXGQrXFwuKlxcZCoiKSkKfQoKY29tbWEgPC0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIGRpZ2l0cyA9IDMsIGJpZy5tYXJrID0gIiwiKQoKY29tbWFfMSA8LSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgZGlnaXRzID0gMSwgYmlnLm1hcmsgPSAiLCIpCgpjb21tYV8yIDwtIGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBkaWdpdHMgPSAyLCBiaWcubWFyayA9ICIsIikKCmNvbW1hX3AgPC0gZnVuY3Rpb24oeCl7CiAgaWYgKHggPCAwLjAwMSl7CiAgICByZXR1cm4oIjwgMC4wMDEiKQogIH0KICBpZiAoeDwwLjAxICYgeD49MC4wMDEpewogICAgcGFzdGUoIj0iLCBmb3JtYXQoeCwgZGlnaXRzID0gMywgYmlnLm1hcmsgPSAiLCIpKQogIH0KICBlbHNlewogICAgcGFzdGUoIj0iLCBmb3JtYXQoeCwgZGlnaXRzID0gMiwgYmlnLm1hcmsgPSAiLCIpKQogIH0KfSAKCmBgYAoKIyBNaXhlZC1lZmZlY3RzIENveCBNb2RlbCBGaXR0aW5nCgpgYGB7ciBkYXRhX2luLCBldmFsID0gRkFMU0V9CnRvX21vZGVsIDwtIHJlYWQuY3N2KCJjbGVhbl90aW1lX3Nlcmllc19yZXZpc2UyMDA2XzIwMTUuY3N2IikKCiNmb3IgdGFibGUgUzQKdHhfaHIgPC0gaGF2ZW46OnJlYWRfc2FzKCJTQUYgMjAxOCBRMy90eF9oci5zYXM3YmRhdCIsIE5VTEwpICU+JSAgCiAgaGF2ZW46OnphcF9mb3JtYXRzKCkgJT4lIGhhdmVuOjp6YXBfbGFiZWxzKCkKCnRvX21vZGVsCmBgYAoKCmBgYHtyIGZvcm11bGFzX25lc3RlZF9tb2RlbHMsIGV2YWwgPSBGQUxTRX0KI3RocmVlLXN0YXR1cywgZG9ub3IgcXVhbGl0eSwgYW5kIHRyYW5zcGxhbnQgeWVhcgp0aHJlZV9zdGF0dXMgPC0gIlN1cnYodF8xLCB0XzIsIGRlYWQpIH4gdHgqKHN0YXRfMiArIHN0YXRfMWIpIAorIHR4X3Jpc2t5X2RvbiArIGVyYV90eCIKCiNzaXgtc3RhdHVzLCBkb25vciBxdWFsaXR5IGFuZCB0cmFuc3BsYW50IHllYXIKc2l4X3N0YXR1cyA8LSAiU3Vydih0XzEsIHRfMiwgZGVhZCkgfiB0eCooc3RhdHVzXzIgKyBzdGF0dXNfMyArIHN0YXR1c180ICsgc3RhdHVzXzYpICsgCnR4X3Jpc2t5X2RvbiArIGVyYV90eCIKYGBgCgoKCmBgYHtyIHJ1bl9mZV9jb3hfbW9kZWxzLCBldmFsID0gRkFMU0V9CmZvcm11bGFzIDwtIGModGhyZWVfc3RhdHVzLHNpeF9zdGF0dXMpCgpmZV9tb2RlbHMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aChmb3JtdWxhcykpCmh6X2xpc3QgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aChmb3JtdWxhcykpCgpmb3IgKGkgaW4gc2VxX2Fsb25nKGZvcm11bGFzKSkgewogIGNveHBoX2ZlIDwtIGNveHBoKGFzLmZvcm11bGEoZm9ybXVsYXNbW2ldXSksIHRvX21vZGVsKQogIHByaW50KGZvcm11bGFzW1tpXV0pCiAgcHJpbnQoY294cGhfZmUpCiAgZmVfbW9kZWxzW1tpXV0gPC0gY294cGhfZmUKCiAgI2VzdGltYXRlIGJhc2VsaW5lIGhhemFyZCBmdW5jdGlvbiB3aGVuIGFsbCBjb3ZhcmlhdGVzIGVxdWFsIHRvIHplcm8gCiAgIyBTdGF0dXMgMUEsIGFmdGVyICJTdGF0dXMgMUEiLCBsb3cgcmlzayBkb25vcgogIGJhc2VoeiA8LSBiYXNlaGF6KGNveHBoX2ZlLCBjZW50ZXJlZD1GQUxTRSkgJT4lIAogICAgbXV0YXRlKGh6X3QgPSBpZl9lbHNlKHRpbWUgPT0xLCBoYXphcmQsIChoYXphcmQgLSBsYWcoaGF6YXJkKSkvKHRpbWUgLWxhZyh0aW1lKSkpLCAKICAgICAgICAgICBoel90X3RpbWUgPSBpZl9lbHNlKHRpbWUgPT0xLCBoel90KnRpbWUsIGh6X3QqKHRpbWUgLWxhZyh0aW1lKSkpLCAKICAgICAgICAgICBjdW1faHogPSBjdW1zdW0oaHpfdF90aW1lKSkgJT4lIHNlbGVjdCh0aW1lLCBoel90KQoKICBoel9saXN0W1tpXV0gPC0gYmFzZWh6Cn0KYGBgCgoKYGBge3IgZml0X21lX21vZGVsLCBldmFsPUZBTFNFIH0KCm1lX21vZGVscyA8LSAgdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aChmb3JtdWxhcykpCgpmb3IgKGkgaW4gc2VxX2Fsb25nKGZvcm11bGFzKSkgewogIGZfY294bWUgPC0gYXMuZm9ybXVsYShwYXN0ZShmb3JtdWxhc1tbaV1dLCAiICsgKDErIHR4fGNlbnRlcikiKSkKICBzdGFydF90aW1lIDwtIFN5cy50aW1lKCkKICB0aHJlZV9zdGF0dXMgPC0gY294bWUoZl9jb3htZSwgZGF0YSA9IHRvX21vZGVsKQogIG1lX21vZGVsc1tbaV1dIDwtIHRocmVlX3N0YXR1cyAKICBlbmRfdGltZSA8LSBTeXMudGltZSgpCiAgZGlmZl90aW1lIDwtIGVuZF90aW1lIC0gc3RhcnRfdGltZQogIHByaW50KGZfY294bWUpCiAgcHJpbnQoZGlmZl90aW1lKQp9CgoKI3NhdmUuaW1hZ2UoIm1vZGVsX2ZpdC5SRGF0YSIpCmBgYAoKCmBgYHtyIGxvYWRfd29ya3NwYWNlX2ltYWdlLCBpbmNsdWRlPUZBTFNFfQpsb2FkKCJlbmRfcmVzdWx0c193aXRoX2FsdHMuUkRhdGEiKQpgYGAKCgojIyBWYXJpYW5jZSBpbiB0cmFuc3BsYW50IGJlbmVmaXQgCgpIZXJlIHdlIHdyaXRlIGEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBiZXR3ZWVuIGNlbnRlciBjb21iaW5hdGlvbiBpbiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiB0cmFuc3BsYW50IG9uIHRoZSBsb2cgaGF6YXJkIHNjYWxlCgokc3Vydml2YWxCZW5lZml0X2kgPSBcbnVfezFpfSAtIFxudV97MGl9JAoKJFZhcihcbnVfe2kxfSAtIFxudV97aTB9KSA9IFZhcih2X3sxaX0pICsgVmFyKFxudV97MGl9KSAtIDIqQ292KHZfezFpfSwgdl97MGl9KSQKCmFuZCBmaW5hbGx5IHNpbmNlIGBjb3htZWAgcmV0dXJucyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcmFuZG9tIGVmZmVjdHMKCiRDb3Yodl97MWl9LCB2X3swaX0pID0gQ29ycih2X3sxaX0sIHZfezBpfSkqXHNpZ21hX3t2X3swaX19XHNpZ21hX3t2X3sxaX19JAoKCmBgYHtyIHZhcl90eF9iZW5lZml0fQp2YXJpYW5jZV9zdXJ2aXZhbF9iZW5lZml0IDwtIGZ1bmN0aW9uKG1lX2NveCl7CiAgdmFyaWFuY2VfZXN0IDwtIG1lX2NveCR2Y29lZltbMV1dCiAgCiAgdmFyX3dhaXQgPC0gdmFyaWFuY2VfZXN0W1sxLDFdXQogIHZhcl90eCA8LSB2YXJpYW5jZV9lc3RbWzIsMl1dCiAgY292X3R4X3dhaXQgPC0gdmFyaWFuY2VfZXN0W1sxLDJdXSpzcXJ0KHZhcmlhbmNlX2VzdFtbMSwxXV0pKnNxcnQodmFyaWFuY2VfZXN0W1syLDJdXSkKICAKICByZXR1cm4odmFyX3dhaXQgKyB2YXJfdHggLSAyKmNvdl90eF93YWl0KQp9CmBgYAoKIyMgMyBzdGF0dXMgYGNveG1lYCByZXN1bHRzCmBgYHtyIHRocmVlX3N0YXR1c19tZV9yZXN1bHRzfQp0aHJlZV9zdGF0dXMgPC0gbWVfbW9kZWxzW1sxXV0KCmJhc2VoeiA8LSBoel9saXN0W1sxXV0KCnRocmVlX3N0YXR1c192YXIgPC0gdmFyaWFuY2Vfc3Vydml2YWxfYmVuZWZpdCh0aHJlZV9zdGF0dXMpCgp0aHJlZV9zdGF0dXMKYGBgClRoZSBjYWxjdWxhdGVkIHZhcmlhbmNlIGluIHRoZSBzdXJ2aXZhbCBiZW5lZml0IG9mIHRyYW5zcGxhbnQgJEIgPSBUeCAtIFdhaXQkIGlzIGByIGNvbW1hKHRocmVlX3N0YXR1c192YXIpYCBvbiBsb2cgaGF6YXJkIHJhdGlvIHNjYWxlIGZvciB0aGUgMy1zdGF0dXMgbW9kZWwKCgojIyA2IHN0YXR1cyBgY294bWVgIHJlc3VsdHMKYGBge3Igc2l4X3N0YXR1c19yZXN1bHRzfQpzaXhfc3RhdHVzIDwtIG1lX21vZGVsc1tbMl1dCgpiYXNlaHpfc2l4X3N0YXQgPC0gaHpfbGlzdFtbMl1dCgpzaXhfc3RhdHVzX3ZhciA8LSB2YXJpYW5jZV9zdXJ2aXZhbF9iZW5lZml0KHNpeF9zdGF0dXMpCgoKc2l4X3N0YXR1cwpgYGAKClRoZSBjYWxjdWxhdGVkIHZhcmlhbmNlIGluIHRoZSBzdXJ2aXZhbCBiZW5lZml0IG9mIHRyYW5zcGxhbnQgJEIgPSBUeCAtIFdhaXQkIGluIHRoZSBzaXgtc3RhdHVzIG1vZGVsIGRlY3JlYXNlZCBieSBhIGZhY3RvciBvZiBgciBjb21tYV8yKCh0aHJlZV9zdGF0dXNfdmFyLXNpeF9zdGF0dXNfdmFyKS90aHJlZV9zdGF0dXNfdmFyKWAgZnJvbSBgciBjb21tYSh0aHJlZV9zdGF0dXNfdmFyKWAgdG8gYHIgY29tbWEoc2l4X3N0YXR1c192YXIpYCBvbiBsb2cgaGF6YXJkIHJhdGlvIHNjYWxlIGNvbXBhcmVkIHRvIHRoZSB0aHJlZS1zdGF0dXMgc3lzdGVtLgoKClxwYWdlYnJlYWsKCiMgU3Vydml2YWwgQmVuZWZpdCBDYWxjdWxhdGlvbnMKYGBge3IgaHJfdHhfaWp9CmhyX3R4X2lqIDwtIGZ1bmN0aW9uKG1vZGVsID0gdGhyZWVfc3RhdHVzLCBkZj0gdG9fbW9kZWwsIGksIGopewogICN0aGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIGxvZyBoYXphcmQgcmF0aW8gb2YgdHJhbnNwbGFudCAKICAjZm9yIHBhdGllbnQgaiB0cmFuc3BsYW50ZWQgYXQgY2VudGVyIGkgZm9yIGEgZ2l2ZW4gY294bWUgbW9kZWwgIAogIGZpeGVkX2VmZmVjdHMgPC0gZml4ZWYobW9kZWwpCiAgeF92YXJzIDwtIG5hbWVzKGZpeGVkX2VmZmVjdHMpCiAgcmVmIDwtIGRhdGEuZnJhbWUocmFuZWYobW9kZWwpW1sxXV0pCiAgcmVmJGNlbnRlciA8LSByb3cubmFtZXMocmVmKQogIHR4X3JlZiA8LSBmaWx0ZXIocmVmLCBjZW50ZXIgPT0gaSkkdHgKICAKICBpc19pbnQgPC0gZnVuY3Rpb24oeCkgZ3JlcGwoInR4OiIsIHgpCiAgaW50cyA8LSB4X3ZhcnNbc2FwcGx5KHhfdmFycywgaXNfaW50KV0KICBub25faW50cyA8LSBzZXRkaWZmKHhfdmFycywgaW50cykKCiAgZF9paiA8LSBkZiAlPiUgZmlsdGVyKFBYX0lEID09IGopICU+JSBncm91cF9ieSh0eCkgJT4lIAogICAgZmlsdGVyKHJvd19udW1iZXIoKT09MSAmIHR4ID09MSkgJT4lIHNlbGVjdChvbmVfb2Yobm9uX2ludHMpKQoKICBoX2lqIDwtIHR4X3JlZiArIHVubmFtZShmaXhlZF9lZmZlY3RzWyd0eCddKQogIGZvciAoeCBpbiBpbnRzKSB7CiAgCSAgZmVfdHggPC0gdW5uYW1lKGZpeGVkX2VmZmVjdHNbeF0pCiAgCSAgY19saXN0IDwtIHN0cnNwbGl0KHgsICI6IikKICAJICBpbnRfdmFyIDwtIGNfbGlzdFtbMV1dWzJdCiAgCSAgaF9paiA8LSBoX2lqICsgZF9paltbaW50X3Zhcl1dKmZlX3R4CiAgfQogIHJldHVybihoX2lqKQp9CgpgYGAKClxwYWdlYnJlYWsKCgojIyBGdW5jdGlvbiB0byBwbG90IHN1cnZpdmFsIGZ1bmN0aW9ucyB1bmRlciB0cmFuc3BsYW50IG9yIG5vIHRyYW5zcGxhbnQKICAKV2FybmluZ3M6CgoqIGZhY3RvciB2YXJpYWJsZXMgYXJlIE5PVCBzdXBwb3J0ZWQsIGV2ZXJ5IGNvdmFyaWF0ZSBNVVNUIGJlIGEgY29udGludW91cyBvciB6ZXJvL29uZS4gIAoqIERvIG5vdCB1c2UgYW55IGNhbmRpZGF0ZSBjb3ZhcmlhdGVzIHdpdGggdHggaW4gdGhlIG5hbWUgdGhpcyB3aWxsIGNhdXNlIHRoaXMgZnVuY3Rpb24gdG8gc2lsZW50bHkgZmFpbC4KKiBEb25vciBjb3ZhcmlhdGVzIHNob3VsZCBiZSBjb2RlZCB3aXRoIGEgdHhfIHByZWZpeAoKYGBge3IgYmVuZWZpdF9lc3RpbWF0ZV9pan0KYl9paiA8LSBmdW5jdGlvbihkZiwgYmFzZV9oeiwgbW9kZWwsIGksIGopewoKCmZpeGVkX2VmZmVjdHMgPC0gZml4ZWYobW9kZWwpCnhfdmFycyA8LSBuYW1lcyhmaXhlZF9lZmZlY3RzKQpyZWYgPC0gZGF0YS5mcmFtZShyYW5lZihtb2RlbClbWzFdXSkKcmVmJGNlbnRlciA8LSByb3cubmFtZXMocmVmKQoKZF9paiA8LSBkZiAlPiUgZmlsdGVyKFBYX0lEID09IGopICU+JSAKICBzZWxlY3QoUFhfSUQsIHRfMSwgdF8yLCBkZWFkLCBvbmVfb2YoeF92YXJzKSkgJT4lIAogIG11dGF0ZSh0aW1lID0gdF8xLCAKICAgICAgICAgdGltZSAgPSBpZmVsc2UodGltZT09MCwgMSwgdGltZSksIAogICAgICAgICBmZV9scCA9IDAsIGxwX25vX3R4ID0gMCkKCmZvciAoeCBpbiB4X3ZhcnMpIHsKCWZlX3ggPC0gdW5uYW1lKGZpeGVkX2VmZmVjdHNbeF0pCgoJaWYoZ3JlcGwoInR4OiIsIHgpID09IEZBTFNFKXsKCQlkX2lqJGNfeCA8LSBkX2lqW1t4XV0KCX0KCSMjYWRkIGNvZGUgdG8gZGVhbCB3aXRoIGludGVyYWN0aW9uIHRlcm1zIGhlcmUKCWlmKGdyZXBsKCJ0eDoiLCB4KSA9PSBUUlVFKXsKCSAgY19saXN0IDwtIHN0cnNwbGl0KHgsICI6IikKCSAgaW50X3ZhciA8LSBjX2xpc3RbWzFdXVsyXQoJICBkX2lqJGNfeCA8LSBkX2lqW1tpbnRfdmFyXV0qZF9paltbInR4Il1dCgl9CgoJZF9paiA8LSBkX2lqICU+JSBtdXRhdGUoZmVfbHAgPSBmZV9scCArIGNfeCpmZV94KSAlPiUgc2VsZWN0KC1jX3gpCn0KCiMjI0h5cG90aGV0aWNhbCB3aGVuIHBhdGllbnQgaGFzIGFsd2F5cyBiZWVuIHRyYW5zcGxhbnRlZApub25fdHhfdGVybXMgPC0gbGFwcGx5KHhfdmFycywgZnVuY3Rpb24oeCkgaWYoZ3JlcGwoInR4IiwgeCkgPT0gRkFMU0UpIHgpCm5vbl90eF90ZXJtcyA8LSBub25fdHhfdGVybXNbLXdoaWNoKHNhcHBseShub25fdHhfdGVybXMsIGlzLm51bGwpKV0KCmZvciAoeCBpbiBub25fdHhfdGVybXMpIHsKCWZlX3ggPC0gdW5uYW1lKGZpeGVkX2VmZmVjdHNbeF0pCglkX2lqJGNfeCA8LSBkX2lqW1t4XV0KCWRfaWogPC0gZF9paiAlPiUgbXV0YXRlKGxwX25vX3R4ID0gbHBfbm9fdHggKyBjX3gqZmVfeCkgJT4lIHNlbGVjdCgtY194KQp9CgoKZF9paiA8LSBsZWZ0X2pvaW4oYmFzZV9oeiwgZF9paiwgYnkgPSBjKCJ0aW1lIikpICU+JSAKICBzZWxlY3QoLXRfMSwgLXRfMikKCmRfaWogPC0gZF9paiAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKG5hLmxvY2YoLiwgbmEucm0gPSBGQUxTRSkpKQoKY3RyX2lfYjAgPC0gcmVmW3JlZiRjZW50ZXIgPT0gaSxdJEludGVyY2VwdApjdHJfaV9iMSA8LSByZWZbcmVmJGNlbnRlciA9PSBpLF0kdHgKCmRfaWogPC0gZF9paiAlPiUgbXV0YXRlKAoJZmVfd2FpdCA9IGxwX25vX3R4LAoJZmVfdHggPSBmZV9scCwKCWN0cl9oel93YWl0ID0gaHpfdCpleHAoZmVfd2FpdCArIGN0cl9pX2IwKSwKCWN0cl9oel90eCA9IGh6X3QqZXhwKGZlX3R4ICsgY3RyX2lfYjAgKyBjdHJfaV9iMSkKCSkgJT4lCgltdXRhdGUod2FpdF9zdXJ2ID0gY3VtcHJvZCgxLWN0cl9oel93YWl0KSkgJT4lIAoJZ3JvdXBfYnkodHgpICU+JSAKCW11dGF0ZSgKCQlzdXJ2X3Bvc3RfdHggPSBpZl9lbHNlKCB0eCA9PTEsIGN1bXByb2QoMS1jdHJfaHpfdHgpLCBOVUxMKSwgCgkJc3Vydl9wb3N0X3R4ID0gbWF4KHdhaXRfc3Vydikqc3Vydl9wb3N0X3R4KSAlPiUgdW5ncm91cCgpCgp0eF9wb2ludCA8LSBkX2lqICU+JSAKICBncm91cF9ieSh0eCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEgJiB0eD09MSkgJT4lIAogIHVuZ3JvdXAoKQoKCmlmIChucm93KHR4X3BvaW50KT09MCkgd2FybmluZyhwYXN0ZTAoIkNhbmRpZGF0ZSAiLCBqLCAiIG5vdCB0cmFuc3BsYW50ZWQiKSkKCmlmIChucm93KHR4X3BvaW50KT4wKSB7CnBsb3RfaV9qIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9zdGVwKGRhdGEgPSBkX2lqLCAKICAgICAgICAgICAgYWVzKHkgPXdhaXRfc3VydiwgCiAgICAgICAgICAgICAgICB4ID0gdGltZSwgCiAgICAgICAgICAgICAgICBjb2xvciA9ICJXYWl0bGlzdCBTdXJ2aXZhbCIpLCAKICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogIGdlb21fc3RlcChkYXRhID0gZF9paiwgCiAgICAgICAgICAgIGFlcyh5ID1zdXJ2X3Bvc3RfdHgsIAogICAgICAgICAgICAgICAgeCA9IHRpbWUsIAogICAgICAgICAgICAgICAgY29sb3IgPSAiUG9zdC10cmFuc3BsYW50IHN1cnZpdmFsIiksIAogICAgICAgICAgICBzaXplID0gMS41KSArIAogIGdlb21fcmliYm9uKGRhdGEgPSBkX2lqLCAKICAgICAgICAgICAgICBhZXMoeD0gdGltZSwgCiAgICAgICAgICAgICAgICAgIHltaW4gPSB3YWl0X3N1cnYsIAogICAgICAgICAgICAgICAgICB5bWF4ID0gc3Vydl9wb3N0X3R4LCAKICAgICAgICAgICAgICAgICAgZmlsbCA9ICJTdXJ2aXZhbCBCZW5lZml0IiksIAogICAgICAgICAgICAgIGFscGhhID0gMC41KSArIAogIGdlb21fcG9pbnQoZGF0YSA9IHR4X3BvaW50LCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgCiAgICAgICAgICAgICAgICAgeSA9IHN1cnZfcG9zdF90eCwgCiAgICAgICAgICAgICAgICAgc2hhcGU9ICJUcmFuc3BsYW50IiksIAogICAgICAgICAgICAgc2l6ZSA9IDUsIGNvbG91ciA9ICJkYXJrZ3JlZW4iKSArIAogIGxhYnMoeCA9ICJUaW1lKGRheXMpIiwgeSA9ICJTdXJ2aXZhbCIsIHNoYXBlID0gIiIsIGZpbGwgPSAiIikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpLCBicmVha3MgPSBzZXEoMCwxLCAwLjI1KSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDM2NTAsIDM2NSkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSBOVUxMLCB2YWx1ZXM9YygiYmx1ZSIsICJyZWQiKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9IGMoImxpZ2h0Ymx1ZSIpKQoJCnJldHVybihwbG90X2lfaikJCn0KCgp9CgpgYGAKCgpccGFnZWJyZWFrCgojIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgNS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQKCgp0aGlzIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgdGhlIHN1cnZpdmFsIGJlbmVmaXQgZm9yIGEgZ2l2ZW4gc2V0IG9mIHRpbWVzIChkZWZhdWx0IGlzIGZpdmUteWVhcnMpLiBDYWxjdWxhdGVzIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbiBjb25kaXRpb25hbCB1cG9uIHJlYWNoaW5nIHRyYW5zcGxhbnQgKCJyZXNldHMiIHRoZSBzdXJ2aXZhbCBjdXJ2ZSB0byAxMDAlIGF0IHRyYW5zcGxhbnQpCgpXYXJuaW5nczoKCiogZmFjdG9yIHZhcmlhYmxlcyBhcmUgTk9UIHN1cHBvcnRlZCwgZXZlcnkgY292YXJpYXRlIE1VU1QgYmUgYSBjb250aW51b3VzIG9yIHplcm8vb25lLiAgCiogRG8gbm90IHVzZSBhbnkgY2FuZGlkYXRlIGNvdmFyaWF0ZXMgd2l0aCB0eCBpbiB0aGUgbmFtZSB0aGlzIHdpbGwgY2F1c2UgdGhpcyBmdW5jdGlvbiB0byBzaWxlbnRseSBmYWlsLgoqIERvbm9yIGNvdmFyaWF0ZXMgc2hvdWxkIGJlIGNvZGVkIHdpdGggYSB0eF8gcHJlZml4CgoKYGBge3Igd2FpdF90eF81X3llYXJ9CmJlbl93YWl0X3R4IDwtIGZ1bmN0aW9uKGRmID0gdG9fbW9kZWwsIAogICAgICAgICAgICAgICAgICAgICAgICBiYXNlX2h6ID0gYmFzZWh6LCAKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSB0aHJlZV9zdGF0dXMsIGksIGosIGVuZF90aW1lcyA9IDE4MjUpewoKCgoKbWF4X2VuZF90aW1lIDwtIG1heChlbmRfdGltZXMpCgpmaXhlZF9lZmZlY3RzIDwtIGZpeGVmKG1vZGVsKQp4X3ZhcnMgPC0gbmFtZXMoZml4ZWRfZWZmZWN0cykKcmVmIDwtIGRhdGEuZnJhbWUocmFuZWYobW9kZWwpW1sxXV0pCnJlZiRjZW50ZXIgPC0gcm93Lm5hbWVzKHJlZikKCmRfaWogPC0gZGYgJT4lIAogIGZpbHRlcihQWF9JRCA9PSBqKSAlPiUgCiAgc2VsZWN0KFBYX0lELCB0XzEsIHRfMiwgZGVhZCwgb25lX29mKHhfdmFycykpICU+JSAKICBtdXRhdGUodGltZSA9IHRfMSwgCiAgICAgICAgIHRpbWUgID0gaWZlbHNlKHRpbWU9PTAsIDEsIHRpbWUpLCAKICAgICAgICAgZmVfbHAgPSAwLCAKICAgICAgICAgbHBfbm9fdHggPSAwKQoKZm9yICh4IGluIHhfdmFycykgewoJZmVfeCA8LSB1bm5hbWUoZml4ZWRfZWZmZWN0c1t4XSkKCglpZihncmVwbCgidHg6IiwgeCkgPT0gRkFMU0UpewoJCWRfaWokY194IDwtIGRfaWpbW3hdXQoJfQoJIyNhZGQgY29kZSB0byBkZWFsIHdpdGggaW50ZXJhY3Rpb24gdGVybXMgaGVyZQoJaWYoZ3JlcGwoInR4OiIsIHgpID09IFRSVUUpewoJICBjX2xpc3QgPC0gc3Ryc3BsaXQoeCwgIjoiKQoJICBpbnRfdmFyIDwtIGNfbGlzdFtbMV1dWzJdCgkgIGRfaWokY194IDwtIGRfaWpbW2ludF92YXJdXSpkX2lqW1sidHgiXV0KCX0KCglkX2lqIDwtIGRfaWogJT4lIG11dGF0ZShmZV9scCA9IGZlX2xwICsgY194KmZlX3gpICU+JSBzZWxlY3QoLWNfeCkKfQoKIyMjSHlwb3RoZXRpY2FsIHdoZW4gcGF0aWVudCBoYXMgYWx3YXlzIGJlZW4gdHJhbnNwbGFudGVkCm5vbl90eF90ZXJtcyA8LSBsYXBwbHkoeF92YXJzLCBmdW5jdGlvbih4KSBpZihncmVwbCgidHgiLCB4KSA9PSBGQUxTRSkgeCkKbm9uX3R4X3Rlcm1zIDwtIG5vbl90eF90ZXJtc1std2hpY2goc2FwcGx5KG5vbl90eF90ZXJtcywgaXMubnVsbCkpXQoKZm9yICh4IGluIG5vbl90eF90ZXJtcykgewoJZmVfeCA8LSB1bm5hbWUoZml4ZWRfZWZmZWN0c1t4XSkKCWRfaWokY194IDwtIGRfaWpbW3hdXQoJZF9paiA8LSBkX2lqICU+JSBtdXRhdGUobHBfbm9fdHggPSBscF9ub190eCArIGNfeCpmZV94KSAlPiUgc2VsZWN0KC1jX3gpCn0KCgpkX2lqIDwtIGxlZnRfam9pbihiYXNlX2h6LCBkX2lqLCBieSA9IGMoInRpbWUiKSkgJT4lIHNlbGVjdCgtdF8xLCAtdF8yKQoKZF9paiA8LSBkX2lqICU+JSAKICBtdXRhdGVfYWxsKGZ1bnMobmEubG9jZiguLCBuYS5ybSA9IEZBTFNFKSkpICU+JSAKICBmaWx0ZXIodHggPT0xKSAlPiUgCiAgbXV0YXRlKHRpbWUgPSB0aW1lIC0gbWluKHRpbWUpKzEpCgpjdHJfaV9iMCA8LSByZWZbcmVmJGNlbnRlciA9PSBpLF0kSW50ZXJjZXB0CmN0cl9pX2IxIDwtIHJlZltyZWYkY2VudGVyID09IGksXSR0eAoKZF9paiA8LSBkX2lqICU+JSBtdXRhdGUoCglmZV93YWl0ID0gbHBfbm9fdHgsCglmZV90eCA9IGZlX2xwLAoJY3RyX2h6X3dhaXQgPSBoel90KmV4cChmZV93YWl0ICsgY3RyX2lfYjApLAoJY3RyX2h6X3R4ID0gaHpfdCpleHAoZmVfdHggKyBjdHJfaV9iMCArIGN0cl9pX2IxKQoJKSAlPiUKCW11dGF0ZSh3YWl0X3N1cnYgPSBjdW1wcm9kKDEtY3RyX2h6X3dhaXQpKSAlPiUgCglncm91cF9ieSh0eCkgJT4lIAoJbXV0YXRlKAoJCXN1cnZfcG9zdF90eCA9IGlmX2Vsc2UoIHR4ID09MSwgY3VtcHJvZCgxLWN0cl9oel90eCksIE5VTEwpLCAKCQlzdXJ2X3Bvc3RfdHggPSBtYXgod2FpdF9zdXJ2KSpzdXJ2X3Bvc3RfdHgpICU+JSB1bmdyb3VwKCkKCgpkX2lqIDwtIGRfaWogJT4lIAogIGZpbHRlcih0aW1lIDw9IG1heF9lbmRfdGltZSkgJT4lIAogIG11dGF0ZShzdXJ2X2JlbmVmaXQgPSBzdXJ2X3Bvc3RfdHggLSB3YWl0X3N1cnYpCgppZiAobnJvdyhkX2lqKT09MCkgd2FybmluZyhwYXN0ZTAoIkNhbmRpZGF0ZSAiLCBqLCAiIG5vdCB0cmFuc3BsYW50ZWQiKSkKCgogIHNfYmVuZWZpdCA8LSB2ZWN0b3IobW9kZSA9ICJudW1lcmljIiwgbGVuZ3RoID0gMikKICAKICB3YWl0XzUgPC0gZmlsdGVyKGRfaWosIHRpbWUgPT0gZW5kX3RpbWVzKSR3YWl0X3N1cnYKICBwb3N0XzUgPC0gZmlsdGVyKGRfaWosIHRpbWUgPT0gZW5kX3RpbWVzKSRzdXJ2X3Bvc3RfdHgKICAKICBpZiAobGVuZ3RoKHdhaXRfNSkgPT0gMCl7CiAgICAgd2FpdF81IDwtIE5BCiAgfQogIAogIGlmIChsZW5ndGgocG9zdF81KT09MCl7CiAgICAgcG9zdF81IDwtIE5BCiAgfQogIAogIHNfYmVuZWZpdFtbMV1dIDwtIHdhaXRfNQogIAogIHNfYmVuZWZpdFtbMl1dIDwtIHBvc3RfNQogIAoJcmV0dXJuKHNfYmVuZWZpdCkKCn0KYGBgCgpccGFnZWJyZWFrCgojIyBEaXN0cmlidXRpb24gb2Ygc3Vydml2YWwgYmVuZWZpdCBhdCBmaXZlIHllYXJzIGZvciBlYWNoIGNlbnRlciAodGhyZWUtc3RhdHVzIHN5c3RlbSkKCldhcm5pbmdzOgoKKiB0aGlzIGxvb3AgdGFrZXMgYWR2YW50YWdlIG9mIHBhcmFsbGVsIHByb2Nlc3NpbmcgYW5kIHdpbGwgdXNlIG1vc3Qgb2YgeW91ciBjb3Jlcy4gCiogRGVzcGl0ZSB0aGlzIGV4cGVjdCBsb25nIGNvbXB1dGF0aW9uYWwgdGltZXMuCmBgYHtyIGJlbmVmaXRfd2FpdF9wb3N0XzUsIGV2YWwgPSBGQUxTRX0KCmRldGVjdENvcmVzKCkKCm5vX2NvcmVzIDwtIGRldGVjdENvcmVzKCkgLSAyCiMgSW5pdGlhdGUgY2x1c3RlcgpjbCA8LSBtYWtlQ2x1c3Rlcihub19jb3JlcywgIHR5cGU9IkZPUksiKQoKY2VudGVyX2xvb3AgPC0gZnVuY3Rpb24oY2VudGVycywgcmVjaXBzLCBjbCl7CgogICNvdXRwdXQgdGliYmxlcwogIHdhaXRfc3VydiA8LSB0aWJibGUocmVjaXBzID0gcmVjaXBzKQogIHBvc3RfdHhfc3VydiA8LSB0aWJibGUocmVjaXBzID0gcmVjaXBzKQogIAogIGZvciAoYyBpbiBjZW50ZXJzKSB7CiAgCWN1cl9jZW50ZXIgPC0gYXMubnVtZXJpYyhjKQogIAlwcmludChwYXN0ZTAoImN1cnJlbnRseSBjYWxjdWxhdGluZyBmb3IgY2VudGVyICIsIGMpKQogIAkKICAJQl9pIDwtIHBhclNhcHBseShjbCwgcl9saXN0LCAKICAJICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSBiZW5fd2FpdF90eChqID0geCwgCiAgCSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGYgPSB0b19tb2RlbCwgCiAgCSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZV9oeiA9IGJhc2VoeiwgCiAgCSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSB0aHJlZV9zdGF0dXMsIAogIAkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBjdXJfY2VudGVyKSkKICAJCiAgCUJfdHJhbnMgPC0gbWF0cml4KEJfaSwgbnJvdyA9IDIsIG5jb2wgPSBsZW5ndGgocmVjaXBzKSkgJT4lIHQoKQogIAlCX3RpYiA8LSAgYXMudGliYmxlKEJfdHJhbnMpIAoKCiAgCXdhaXQgPC0gQl90aWIgJT4lIHNlbGVjdChWMSkgJT4lIGNiaW5kKHJlY2lwcykKICAJY29sbmFtZXMod2FpdCkgPC0gYyhjLCAicmVjaXBzIikKICAJCiAgCXBvc3RfdHggPC0gQl90aWIgJT4lIHNlbGVjdChWMikgJT4lIGNiaW5kKHJlY2lwcykKICAJY29sbmFtZXMocG9zdF90eCkgPC0gYyhjLCAicmVjaXBzIikKICAJCiAgCXdhaXRfc3VydiA8LSB3YWl0X3N1cnYgJT4lIGxlZnRfam9pbih3YWl0LCBieSA9ICJyZWNpcHMiKQogIAkKICAJcG9zdF90eF9zdXJ2IDwtIHBvc3RfdHhfc3VydiAlPiUgbGVmdF9qb2luKHBvc3RfdHgsIGJ5ID0gInJlY2lwcyIpCiAgCQoKICB9CiAgYmVuZWZpdCA8LSBsaXN0KHdhaXRfc3VydiwgcG9zdF90eF9zdXJ2KQogIAogIHJldHVybihiZW5lZml0KQp9CgoKcl9saXN0IDwtIHVuaXF1ZShmaWx0ZXIodG9fbW9kZWwsIHR4ID09MSkkUFhfSUQpCmNfbGlzdCA8LSBhcy5udW1lcmljKHJvdy5uYW1lcyhyYW5lZih0aHJlZV9zdGF0dXMpW1sxXV0pKQoKCmJ5X3RpbWVfdGliYmxlcyA8LSBjZW50ZXJfbG9vcChjX2xpc3QsIHJfbGlzdCwgY2wpCgoKc3RvcENsdXN0ZXIoY2wpCgpmaXZlX3lyX3dhaXQgPC0gYnlfdGltZV90aWJibGVzW1sxXV0KCmZpdmVfeXJfcG9zdCA8LSBieV90aW1lX3RpYmJsZXNbWzJdXQpgYGAKCiMjIE1ha2UgZGF0YXNldHMgZm9yIHVzZSBpbiBGaWd1cmVzIGFuZCBSZXN1bHRzIFNlY3Rpb24KYGBge3IgbWFrZV9jZW50ZXJfbGV2ZWxfZGF0YXNldCwgZXZhbCA9IEZBTFNFfQoKI3JlY2lwaWVudHMKcmVjaXBzIDwtIHRvX21vZGVsICU+JSBncm91cF9ieShQWF9JRCkgJT4lIGZpbHRlcih0eCA9PSAxKSAlPiUgdW5ncm91cCgpCgojbWFyZ2luYWwgZGlzdHJpYnV0aW9uIG9mIGJlbmVmaXQgb2YgdHJhbnNwbGFudAptYXJnaW5hbF9oYXphcmRzIDwtIG1hcHBseShocl90eF9paiwgaSA9IHJlY2lwcyRjZW50ZXIsIGogPSByZWNpcHMkUFhfSUQpCgptYXJnaW5hbF93YWl0c19wb3N0cyA8LSBtYXBwbHkoYmVuX3dhaXRfdHgsIGkgPSByZWNpcHMkY2VudGVyLCBqID0gcmVjaXBzJFBYX0lEKQoKbWFyZ2luYWxfd2FpdHMgPC0gbWFyZ2luYWxfd2FpdHNfcG9zdHNbMSxdCm1hcmdpbmFsX3Bvc3RzIDwtIG1hcmdpbmFsX3dhaXRzX3Bvc3RzWzIsXQoKcG9wX3R4X2h6IDwtIHJlY2lwcyAlPiUgY2JpbmQobWFyZ2luYWxfaGF6YXJkcywgbWFyZ2luYWxfd2FpdHMsIG1hcmdpbmFsX3Bvc3RzKSAlPiUgCiAgbXV0YXRlKGxvZ19oYXphcmQgPSBtYXJnaW5hbF9oYXphcmRzLCAKICAgICAgICAgaHIgPSBleHAobG9nX2hhemFyZCksCiAgICAgICAgIGJlbmVmaXQ9IG1hcmdpbmFsX3Bvc3RzLSBtYXJnaW5hbF93YWl0cykKCnJfbGlzdCA8LSB1bmlxdWUoZmlsdGVyKHRvX21vZGVsLCB0eCA9PTEpJFBYX0lEKQpjX2xpc3QgPC0gYXMubnVtZXJpYyhyb3cubmFtZXMocmFuZWYodGhyZWVfc3RhdHVzKVtbMV1dKSkKCmNlbnRlcl9PUE8gPC0gcmVjaXBzICU+JSBzZWxlY3QoY2VudGVyLCBPUE8pICU+JSAKICBncm91cF9ieShjZW50ZXIsIE9QTykgJT4lIAogIHN1bW1hcmlzZShudW1fdHggPSBuKCkpICU+JSB1bmdyb3VwKCkKCnJlX2VmZmVjdHMgPC0gZGF0YS5mcmFtZShyYW5lZih0aHJlZV9zdGF0dXMpW1sxXV0pCgpyZV9lZmZlY3RzJGNlbnRlciA8LSByb3cubmFtZXMocmVfZWZmZWN0cykKCmNvbG5hbWVzKHJlX2VmZmVjdHMpWzJdIDwtICJ0eF9yZSIKCiNtYWtlIGEgY2VudGVyIGxldmVsIGRhdGFzZXQgb2YgcmFuZG9tIGVmZmVjdHMKY2VudGVyX3JlIDwtIGNlbnRlcl9PUE8gJT4lIAogIGxlZnRfam9pbihyZV9lZmZlY3RzICU+JSBtdXRhdGUoY2VudGVyID0gYXMubnVtZXJpYyhjZW50ZXIpKSkgJT4lIAogIG11dGF0ZSh0eF9leHAgPSBleHAodHhfcmUpLAogICAgICAgICBiZW5lZml0ID0gdHhfcmUtSW50ZXJjZXB0LAogICAgICAgICBpbnRlcmNlcHRfZXhwID0gZXhwKEludGVyY2VwdCkpICU+JSB1bmdyb3VwKCkKCmNlbnRlcl9yZSA8LSBjZW50ZXJfcmUgJT4lIGxlZnRfam9pbihmaXZlX3llYXJfbWVhbnMpCgojY2FsY3VsYXRlIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGNlbnRlcgptaW5fdHhfZXhwIDwtIG1pbihjZW50ZXJfcmUkdHhfZXhwKQoKbWF4X3R4X2V4cCA8LSBtYXgoY2VudGVyX3JlJHR4X2V4cCkKCm1pbl9pbnRfZXhwIDwtIG1pbihjZW50ZXJfcmUkaW50ZXJjZXB0X2V4cCkKCm1heF9pbnRfZXhwIDwtIG1heChjZW50ZXJfcmUkaW50ZXJjZXB0X2V4cCkKYGBgCgoKCmBgYHtyIHN1bW1hcml6ZV9maXZlX3llYXJfYmVuZWZpdCwgZXZhbCA9IEZBTFNFfQoKI21ha2UgYmVuZWZpdCBkYXRhZnJhbWUtIGh5cG90aGV0aWNhbCBlc3RpbWF0ZXMgYXMgaWYgYWxsIHJlY2lwaWVudHMgd2VyZSB0cmFuc3BsYW50ZWQgYXQgdGhlIGNlbnRlcgpjb2xuYW1lcyhmaXZlX3lyX3dhaXQpIDwtIGMoInJlY2lwcyIsIGNfbGlzdCkKY29sbmFtZXMoZml2ZV95cl9wb3N0KSA8LSBjKCJyZWNpcHMiLCBjX2xpc3QpCgpNIDwtIG1lcmdlKGZpdmVfeXJfcG9zdCxmaXZlX3lyX3dhaXQsYnk9InJlY2lwcyIpCgpiZW5fZml2ZV95ZWFyX29ubHkgPC0gTVssZ3JlcGwoIipcXC54JCIsbmFtZXMoTSkpXSAtIE1bLGdyZXBsKCIqXFwueSQiLG5hbWVzKE0pKV0KCmNiaW5kKE1bLDEsZHJvcD1GQUxTRV0sYmVuX2ZpdmVfeWVhcl9vbmx5KQpyZW1vdmUoTSkKCmZpdmVfeWVhcl93YWl0cyA8LSBmaXZlX3lyX3dhaXQgJT4lIHNlbGVjdCgtcmVjaXBzKSAlPiUgCiAgc3VtbWFyaXNlX2FsbChtZWFuLCBuYS5ybSA9VFJVRSkgJT4lIAogIGdhdGhlcih2YWx1ZSA9IG1lYW5fZml2ZV95ZWFyX3dhaXQsIGtleSA9IGNlbnRlcikgJT4lIAogIHNlbGVjdChjZW50ZXIsIG1lYW5fZml2ZV95ZWFyX3dhaXQpICU+JSBtdXRhdGUoY2VudGVyID0gYXMubnVtZXJpYyhjZW50ZXIpKQoKZml2ZV95ZWFyX3Bvc3RzIDwtIGZpdmVfeXJfcG9zdCAlPiUgc2VsZWN0KC1yZWNpcHMpICU+JSAKICBzdW1tYXJpc2VfYWxsKG1lYW4sIG5hLnJtID1UUlVFKSAlPiUgCiAgZ2F0aGVyKHZhbHVlID0gbWVhbl9maXZlX3llYXJfcG9zdCwga2V5ID0gY2VudGVyKSAlPiUgCiAgc2VsZWN0KGNlbnRlciwgbWVhbl9maXZlX3llYXJfcG9zdCkgJT4lIG11dGF0ZShjZW50ZXIgPSBhcy5udW1lcmljKGNlbnRlcikpCgoKI2NlbnRlciBsZXZlbCBkYXRhc2V0IG9mIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgY2FzZS1taXggYWRqdXN0ZWQgCiNmaXZlLXllYXIgbWVhbiB3YWl0bGlzdCwgcG9zdC10cmFuc3BsYW50LCBhbmQgc3Vydml2YWwgYmVuZWZpdHMKZml2ZV95ZWFyX21lYW5zIDwtIGJlbl9maXZlX3llYXJfb25seSAlPiUgCiAgc3VtbWFyaXNlX2FsbChmdW5zKG1lYW4sIAogICAgICAgICAgICAgICAgICAgICBtZWRpYW4sIAogICAgICAgICAgICAgICAgICAgICBzZCwgCiAgICAgICAgICAgICAgICAgICAgIElRUiwgCiAgICAgICAgICAgICAgICAgICAgIGxvd1FSID0gcXVhbnRpbGUoLiwgcHJvYnM9MC4yNSksIAogICAgICAgICAgICAgICAgICAgICB1cFFSID0gcXVhbnRpbGUoLiwgcHJvYnM9MC43NSkpLCBuYS5ybSA9IFRSVUUpICU+JQogIGdhdGhlcihrZXkgPSAia2V5IiwgdmFsdWUgPSAidmFsdWUiKSAlPiUKICBzZXBhcmF0ZShrZXksIGMoImNlbnRlciIsICJzdGF0IiksIHNlcCA9ICJfIikgJT4lCiAgc3ByZWFkKHN0YXQsIHZhbHVlKSAlPiUgCiAgbXV0YXRlKGNlbnRlciA9IG51bWV4dHJhY3QoY2VudGVyKSwgbWVhbl9maXZlX3llYXIgPSBtZWFuKSAlPiUgc2VsZWN0KC1tZWFuKSAlPiUKICBsZWZ0X2pvaW4oZml2ZV95ZWFyX3dhaXRzLCBieSA9ICJjZW50ZXIiKSAlPiUgCiAgbGVmdF9qb2luKGZpdmVfeWVhcl9wb3N0cywgYnkgPSAiY2VudGVyIikgJT4lICAKICBsZWZ0X2pvaW4oY2VudGVyX09QTywgYnkgPSAiY2VudGVyIikKCmZpdmVfeWVhcl9tZWFucyA8LSBmaXZlX3llYXJfbWVhbnMgJT4lCiAgbXV0YXRlKHNlX21lYW4gPSBzZC9zcXJ0KG51bV90eCksCiAgICAgICAgIHVwcGVyX2NpID0gbWVhbl9maXZlX3llYXIgKyAxLjk2KnNlX21lYW4sCiAgICAgICAgIGxvd2VyX2NpID0gbWVhbl9maXZlX3llYXIgLSAxLjk2KnNlX21lYW4sCiAgICAgICAgIHNpZ19iZXR0ZXIgPSBpZl9lbHNlKGxvd2VyX2NpID5tZWFuKGZpdmVfeWVhcl9tZWFucyRtZWFuX2ZpdmVfeWVhciksIDEsIDApLAogICAgICAgICBzaWdfd29yc2UgPSBpZl9lbHNlKHVwcGVyX2NpIDxtZWFuKGZpdmVfeWVhcl9tZWFucyRtZWFuX2ZpdmVfeWVhciksIDEsIDApLAogICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPSBjYXNlX3doZW4oCiAgICAgICAgICAgbG93ZXJfY2kgPm1lYW4oZml2ZV95ZWFyX21lYW5zJG1lYW5fZml2ZV95ZWFyKSB+ICJIaWdoIiwKICAgICAgICAgICB1cHBlcl9jaSA8bWVhbihmaXZlX3llYXJfbWVhbnMkbWVhbl9maXZlX3llYXIpIH4gIkxvdyIsCiAgICAgICAgICAgVFJVRSB+ICJBdmVyYWdlIgogICAgICAgICApLCBjZW50ZXJfcGVyZm9ybWFuY2UgPSBmYWN0b3IoY2VudGVyX3BlcmZvcm1hbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkxvdyIsICJBdmVyYWdlIiwgIkhpZ2giKSkpCgpgYGAKCmBgYHtyIHNpeF9zdGF0dXNfcG9wLCB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9CiNtYXJnaW5hbCBkaXN0cmlidXRpb24gb2YgYmVuZWZpdCBvZiB0cmFuc3BsYW50IHVuZGVyIHNpeCBzdGF0dXMgbW9kZWwKbWFyZ2luYWxfaGF6YXJkc182X3N0YXQgPC0gbWFwcGx5KGhyX3R4X2lqLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgPSByZWNpcHMkY2VudGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGogPSByZWNpcHMkUFhfSUQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9yZUFyZ3MgPSBsaXN0KG1vZGVsID0gc2l4X3N0YXR1cykpCgptYXJnaW5hbF93YWl0c19wb3N0c182X3N0YXQgPC0gbWFwcGx5KGJlbl93YWl0X3R4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpID0gcmVjaXBzJGNlbnRlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaiA9IHJlY2lwcyRQWF9JRCwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1vcmVBcmdzID0gbGlzdChiYXNlX2h6ID0gYmFzZWh6X3NpeF9zdGF0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbCA9IHNpeF9zdGF0dXMpKQoKbWFyZ2luYWxfd2FpdHNfNl9zdGF0IDwtIG1hcmdpbmFsX3dhaXRzX3Bvc3RzXzZfc3RhdFsxLF0KbWFyZ2luYWxfcG9zdHNfNl9zdGF0IDwtIG1hcmdpbmFsX3dhaXRzX3Bvc3RzXzZfc3RhdFsyLF0KCgpwb3BfdHhfaHpfNl9zdGF0IDwtIHJlY2lwcyAlPiUgY2JpbmQobWFyZ2luYWxfd2FpdHNfNl9zdGF0LCBtYXJnaW5hbF9wb3N0c182X3N0YXQpICU+JSAKICBtdXRhdGUoYmVuZWZpdF82ID0gbWFyZ2luYWxfcG9zdHNfNl9zdGF0IC0gbWFyZ2luYWxfd2FpdHNfNl9zdGF0KQoKI25vdCBydW4tIHNhdmUgd29ya3NwYWNlIGltYWdlCiNzYXZlLmltYWdlKCJtb2RlbF9maXRfMDZfMTVfd19iZW5lZml0cy5SRGF0YSIpCmBgYAoKXHBhZ2VicmVhawoKIyBGaWd1cmVzCgoKCiMjIEZpZ3VyZSAyOiBCZXR3ZWVuLWNlbnRlciBWYXJpYXRpb24gaW4gdGhlIFN1cnZpdmFsIEJlbmVmaXQgQXNzb2NpYXRlZCB3aXRoIEhlYXJ0IFRyYW5zcGxhbnRhdGlvbgpgYGB7ciBjYXRlcGlsbGFyX3Bsb3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9IEZBTFNFfQp0b19wbG90IDwtIGZpdmVfeWVhcl9tZWFucyAlPiUgYXJyYW5nZShtZWFuX2ZpdmVfeWVhcikgJT4lIG11dGF0ZShpbmRleCA9IHJvd19udW1iZXIoKSkKCgpnX2xlZ2VuZDwtZnVuY3Rpb24oYS5ncGxvdCl7CiAgdG1wIDwtIGdncGxvdF9ndGFibGUoZ2dwbG90X2J1aWxkKGEuZ3Bsb3QpKQogIGxlZyA8LSB3aGljaChzYXBwbHkodG1wJGdyb2JzLCBmdW5jdGlvbih4KSB4JG5hbWUpID09ICJndWlkZS1ib3giKQogIGxlZ2VuZCA8LSB0bXAkZ3JvYnNbW2xlZ11dCiAgcmV0dXJuKGxlZ2VuZCl9CgpjYXRlcGlsbGFyIDwtIGdncGxvdCh0b19wbG90LCBhZXMoeCA9IGluZGV4LCAKICAgICAgICAgICAgICAgICAgICB5ID0gbWVhbl9maXZlX3llYXIqMTAwLCAKICAgICAgICAgICAgICAgICAgICB5bWluID0gbG93ZXJfY2kqMTAwLCAKICAgICAgICAgICAgICAgICAgICB5bWF4ID0gdXBwZXJfY2kqMTAwLCAKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNlbnRlcl9wZXJmb3JtYW5jZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9lcnJvcmJhcigpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiQ2VudGVyIGJlbmVmaXQ6IiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPSBjKCJyZWQzIiwiYmxhY2siLCJuYXZ5Ymx1ZSIpLCAKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQoKSkgKwogIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDEsIDExMykpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDI1LCA2MCwgNSksIGxpbWl0cyA9IGMoMjUsIDYwKSkgKwogIGxhYnMoeSA9ICJBYnNvbHV0ZSBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBcbm9mIGhlYXJ0IHRyYW5zcGxhbnQgKCUpIiwKICAgICAgIHggPSAiQ2VudGVyIiwgY29sb3IgPSAiIikgKyAgCiAgdGhlbWVfZmV3KCkgKyAKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KCksIAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgpLCAKICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEyKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAwLjI1KSwKICAgICAgICBsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpIAoKCmJveCA8LSBnZ3Bsb3QodG9fcGxvdCAlPiUgbXV0YXRlKGFsbCA9ICIgIiksIGFlcyh4ID0gYWxsLCB5ID0gMTAwKm1lYW5fZml2ZV95ZWFyKSkgKyAKICBnZW9tX2JveHBsb3QoKSArCiAgc3RhdF9ib3hwbG90KGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuNSkgKwogIGdlb21fcG9pbnQoeSA9IG1lYW4odG9fcGxvdCRtZWFuX2ZpdmVfeWVhcikqMTAwLCAKICAgICAgICAgICAgIGFlcyh4ID1hbGwsIHNoYXBlID0gIm1lYW4iKSwgCiAgICAgICAgICAgICBzaXplPTQsIGZpbGwgPSAiZ3JheSIsIGFscGhhID0gMC41ICkrIAogIHRoZW1lX2ZldygpICsKICBsYWJzKHggPSAiICIsIHNoYXBlID0gIiAiKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDIzKSArIAogIHRoZW1lKAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSAgZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0gImJvdHRvbSIsCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb249J2xlZnQnKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMjUsIDYwKSwgYnJlYWtzID0gc2VxKDI1LCA2MCwgNSkpCgpmaWdfMiA8LSBncmlkLmFycmFuZ2UoY2F0ZXBpbGxhciwgYm94LAogICAgICAgICAgICAgICAgICAgICAgICAgbnJvdz0xLCB3aWR0aHMgPSBjKDEsIDAuMjUpKQoKbnVtX2hpZ2ggPC0gdGFibGUoZml2ZV95ZWFyX21lYW5zJGNlbnRlcl9wZXJmb3JtYW5jZSlbIkhpZ2giXVtbMV1dCgpudW1fbG93IDwtIHRhYmxlKGZpdmVfeWVhcl9tZWFucyRjZW50ZXJfcGVyZm9ybWFuY2UpWyJMb3ciXVtbMV1dCgptYXhfYmVuZWZpdCA8LSBjb21tYV8yKDEwMCptYXgodG9fcGxvdCRtZWFuX2ZpdmVfeWVhcikpCgoKbWluX2JlbmVmaXQgPC0gY29tbWFfMigxMDAqbWluKHRvX3Bsb3QkbWVhbl9maXZlX3llYXIpKQoKCmhpZ2hfcXJ0XzUgPC0gY29tbWFfMigxMDAqcXVhbnRpbGUodG9fcGxvdCRtZWFuX2ZpdmVfeWVhciwgcHJvYnMgPSAwLjc1KSkKCmxvd19xcnRfNSA8LSBjb21tYV8yKDEwMCpxdWFudGlsZSh0b19wbG90JG1lYW5fZml2ZV95ZWFyLCBwcm9icyA9IDAuMjUpKQoKbWVkaWFuXzUgPC0gY29tbWFfMigxMDAqbWVkaWFuKHRvX3Bsb3QkbWVhbl9maXZlX3llYXIpKQoKZ2dzYXZlKCAiZmlnXzIucGRmIiwgcGxvdCA9IGZpZ18yLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpCmBgYApCZXR3ZWVuLWNlbnRlciB2YXJpYXRpb24gaW4gdGhlIGFic29sdXRlIGltcHJvdmVtZW50IGluIG1lYW4gZml2ZS15ZWFyIHN1cnZpdmFsIGFzc29jaWF0ZWQgd2l0aCBoZWFydCB0cmFuc3BsYW50YXRpb24uIENhdGVycGlsbGFyIHBsb3QgKGxlZnQpIG9mIGNlbnRlciBlc3RpbWF0ZXMgY2FzZS1taXggYWRqdXN0ZWQgZm9yIHRpbWUgZnJvbSBsaXN0aW5nIHRvIHRyYW5zcGxhbnQsIHdhaXRsaXN0IFN0YXR1cywgeWVhciBvZiBsaXN0aW5nLCBkb25vciBxdWFsaXR5LCBhbmQgY29sZCBpc2NoZW1pYyB0aW1lLiBOaW5ldHktZml2ZSBwZXJjZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBjb25zdHJ1Y3RlZCB1c2luZyB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBmaXZlLXllYXIgc3Vydml2YWwgZXN0aW1hdGVzIGZvciB0aGUgZW50aXJlIHN0dWR5IHBvcHVsYXRpb24gYW5kIHRoZSBudW1iZXIgb2YgdHJhbnNwbGFudHMgcGVyZm9ybWVkIGF0IGVhY2ggY2VudGVyIGR1cmluZyB0aGUgc3R1ZHkgcGVyaW9kLiBDb21wYXJlZCB0byB0aGUgbWVhbiBjZW50ZXIsIGByIG51bV9oaWdoYCBjZW50ZXJzIChgciBjb21tYV8yKDEwMCpudW1faGlnaC9ucm93KGNlbnRlcl9yZSkpYCUpIGhhZCBzaWduaWZpY2FudGx5IGhpZ2hlciBzdXJ2aXZhbCBiZW5lZml0IGFuZCBgciBudW1fbG93YCBjZW50ZXJzIChgciBjb21tYV8yKDEwMCpudW1fbG93L25yb3coY2VudGVyX3JlKSlgJSkgaGFkIGxvd2VyIGJlbmVmaXQuCgpUaGUgYWRqdXN0ZWQgZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgdmFyaWVkIHN1YnN0YW50aWFsbHkgYnkgY2VudGVyLCByYW5naW5nIGZyb20gYHIgbWluX2JlbmVmaXRgJSB0byBgciBtYXhfYmVuZWZpdGAlLCBtZWRpYW4gYHIgbWVkaWFuXzVgIGFuZCBJUVIgW2ByIGxvd19xcnRfNWAlIC0gYHIgaGlnaF9xcnRfNWAlXSAoQm94IHBsb3QsIHJpZ2h0KS4gV2hpc2tlcnMgcmVwcmVzZW50IHNtYWxsZXN0IGFuZCBsYXJnZXN0IG9ic2VydmF0aW9ucyB3aXRoaW4gMS41IHRpbWVzIHRoZSBJUVIgb2YgdGhlIGhpbmdlcywgcG9pbnRzIHJlcHJlc2VudCBvdXRsaWVycyBiZXlvbmQgdGhpcyByYW5nZS4gVGhlIG1lYW4gb2YgY2VudGVyIGZpdmUteWVhciBzdXJ2aXZhbCBiZW5lZml0cyBpcyByZXByZXNlbnRlZCBieSBhIGdyYXkgZGlhbW9uZC4gCgoKXHBhZ2VicmVhawoKIyMgRmlndXJlIDM6IFJlbGF0aW9uc2hpcCBiZXR3ZWVuIENhbmRpZGF0ZSBTdXJ2aXZhbCBvbiB0aGUgV2FpdGxpc3QsIFJlY2lwaWVudCBQb3N0LVRyYW5zcGxhbnQgT3V0Y29tZXMsIGFuZCB0aGUgQmVuZWZpdCBvZiBIZWFydCBUcmFuc3BsYW50YXRpb24KYGBge3IgY29tYmluZWRfZmlndXJlXzRfZGlzY3JldGUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9IEZBTFNFfQoKcGFuZWxfQSA8LSBnZ3Bsb3QoZGF0YSA9IGNlbnRlcl9yZSwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gMTAwKm1lYW5fZml2ZV95ZWFyX3dhaXQsIAogICAgICAgICAgICAgICAgICAgICAgeSA9IDEwMCptZWFuX2ZpdmVfeWVhcikpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjZW50ZXJfcGVyZm9ybWFuY2UpLCBzaXplID0gMi41LCBhbHBoYSA9IDAuOSkgKwogICNhbm5vdGF0ZSgibGFiZWwiLCB4ID0gMjUsIHkgPSAzMCwgbGFiZWwgPSBwYXN0ZTAoInIgPSAiLCBjb3JfbW9kZWwpLCBzaXplID0gNSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJGaXZlLXllYXIgc3Vydml2YWwgd2l0aG91dCB0cmFuc3BsYW50ICglKSIsIAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDE4LCA0NCksIAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSAgYygyMCwgMjUsIDMwLCAzNSwgNDApKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNlbnRlciBmaXZlLXllYXIgc3VyaXZhbCBiZW5lZml0ICglKSIsIAogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDI3LCA2MCksIGJyZWFrcyA9IHNlcSgzMCwgNjAsIDUpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkNlbnRlciBiZW5lZml0OiIsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJyZWQzIiwiYmxhY2siLCJuYXZ5Ymx1ZSIpKSArCiAgdGhlbWVfZmV3KCkgKyAKICBnZ3RpdGxlKCJQYW5lbCBBIikgKyAKICB0aGVtZShsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwgCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjI1KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEyKSwKICAgICAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIikpCgoKCm15bGVnZW5kIDwtIGdfbGVnZW5kKHBhbmVsX0EpCgoKCnBhbmVsX0IgPC0gZ2dwbG90KGRhdGEgPSBjZW50ZXJfcmUsIAogICAgICAgICAgICAgICAgICBhZXMoeCA9IG1lYW5fZml2ZV95ZWFyX3Bvc3QqMTAwLCB5ID0gMTAwKm1lYW5fZml2ZV95ZWFyKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNlbnRlcl9wZXJmb3JtYW5jZSksIHNpemUgPSAyLjUsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiRml2ZS15ZWFyIHBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCAoJSkiLCAKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyg2MywgODkpLCAKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gIGMoNjUsIDcwLCA3NSwgODAsIDg1KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDI3LCA2MCksIGJyZWFrcyA9IHNlcSgzMCwgNjAsIDUpKSArCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQzIiwiYmxhY2siLCJuYXZ5Ymx1ZSIpKSArCiAgdGhlbWVfZmV3KCkgKwogIGdndGl0bGUoIlBhbmVsIEIiKSsKICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmJvcmRlciA9ICBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgoKCmZpZ18zIDwtIGdyaWQuYXJyYW5nZSgKICBhcnJhbmdlR3JvYihwYW5lbF9BICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgCiAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAwLjI1KSksCiAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbF9CLAogICAgICAgICAgICAgICAgICAgICAgICAgbnJvdz0xLCB3aWR0aHMgPSBjKDEsIDAuOTUpKSwKICAgICAgICAgICAgICAgICAgICAgIG15bGVnZW5kLCAKICAgICAgICAgICAgIG5yb3c9MixoZWlnaHRzPWMoMTAsIDIuMikpCgoKc2xvcGVfd2FpdGxpc3QgPC0gbG0obWVhbl9maXZlX3llYXIgfiBtZWFuX2ZpdmVfeWVhcl93YWl0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY2VudGVyX3JlKQoKc2xvcGVfcG9zdCA8LSBsbShtZWFuX2ZpdmVfeWVhciB+IG1lYW5fZml2ZV95ZWFyX3Bvc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjZW50ZXJfcmUpCgpwY3RfYmVuZWZpdF9pbmNyZWFzZV9wZXJfbmVnXzEwIDwtIGNvbW1hXzIoCiAgMTAqLXNsb3BlX3dhaXRsaXN0JGNvZWZmaWNpZW50c1tbMl1dKQoKY2lfc2xvcGVfd2FpdF9sb3cgPC0gY29tbWFfMigxMCotY29uZmludChzbG9wZV93YWl0bGlzdCwgJ21lYW5fZml2ZV95ZWFyX3dhaXQnLCBsZXZlbD0wLjk1KVsxLDFdKQoKY2lfc2xvcGVfd2FpdF91cCA8LSBjb21tYV8yKDEwKi1jb25maW50KHNsb3BlX3dhaXRsaXN0LCAnbWVhbl9maXZlX3llYXJfd2FpdCcsIGxldmVsPTAuOTUpWzEsMl0pCgoKcGN0X2JlbmVmaXRfaW5jcmVhc2VfcG9zdCA8LSBjb21tYV8yKDEwKnNsb3BlX3Bvc3QkY29lZmZpY2llbnRzW1syXV0pCgoKY2lfc2xvcGVfcG9zdF9sb3cgPC0gY29tbWFfMigxMCotY29uZmludChzbG9wZV9wb3N0LCAnbWVhbl9maXZlX3llYXJfcG9zdCcsIGxldmVsPTAuOTUpWzEsMV0pCgpjaV9zbG9wZV9wb3N0X3VwIDwtIGNvbW1hXzIoMTAqLWNvbmZpbnQoc2xvcGVfcG9zdCwgJ21lYW5fZml2ZV95ZWFyX3Bvc3QnLCBsZXZlbD0wLjk1KVsxLDJdKQoKZ2dzYXZlKCJmaWdfMy5wZGYiLCBwbG90ID0gZmlnXzMpCmBgYApNZWFuIGZpdmUteWVhciBzdXJ2aXZhbCB3aXRob3V0IHRyYW5zcGxhbnQsIGZpdmUteWVhciBwb3N0LXRyYW5zcGxhbnQgc3Vydml2YWwsIGFuZCBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBmb3IgZWFjaCBVUyBoZWFydCB0cmFuc3BsYW50IGNlbnRlci4gVGhlcmUgd2FzIGEgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIFN0YXR1cy1hZGp1c3RlZCBtZWRpY2FsIHVyZ2VuY3kgb2YgY2FuZGlkYXRlcyBsaXN0ZWQgYnkgZWFjaCBjZW50ZXIgKGFzIG1lYXN1cmVkIGJ5IHJpc2sgb2YgZGVhdGggb24gdGhlIHdhaXRsaXN0KSBhbmQgdGhlIGJlbmVmaXQgb2YgdHJhbnNwbGFudGF0aW9uIG1lYXN1cmVkIGJ5IGZpdmUteWVhciBzdXJ2aXZhbCBiZW5lZml0IChsZWZ0IHBhbmVsKS4gIEZvciBldmVyeSAxMCUgZGVjcmVhc2UgaW4gZXhwZWN0ZWQgY2FuZGlkYXRlIHdhaXRsaXN0IHN1cml2YWwsIHRoZXJlIHdhcyBhIGByIHBjdF9iZW5lZml0X2luY3JlYXNlX3Blcl9uZWdfMTBgJSBpbmNyZWFzZSBpbiBlc3RpbWF0ZWQgc3Vydml2YWwgYmVuZWZpdCBhc3NvY2lhdGVkIHdpdGggaGVhcnQgdHJhbnNwbGFudCAgKDk1JSBDSSBgciBjaV9zbG9wZV93YWl0X3VwYCUgLSBgciBjaV9zbG9wZV93YWl0X2xvd2AlKS4gSW4gY29udHJhc3QsIHRoZXJlIHdhcyBubyBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgYmV0d2VlbiBwb3N0LXRyYW5zcGxhbnQgc3Vydml2YWwgYW5kIGJlbmVmaXQgKCtgciBwY3RfYmVuZWZpdF9pbmNyZWFzZV9wb3N0YCUsIDk1JSBDSSBgciBjaV9zbG9wZV9wb3N0X3VwYCUtIGByIGNpX3Nsb3BlX3Bvc3RfbG93YCUpIChyaWdodCBwYW5lbCkuCgoKXHBhZ2VicmVhawoKIyMgRmlndXJlIDRBOiBGaXZlLXllYXIgU3Vydml2YWwgQmVuZWZpdCBBc3NvY2lhdGVkIHdpdGggSGVhcnQgVHJhbnNwbGFudGF0aW9uIGJ5IFRocmVlLXN0YXR1cyBhdCBUcmFuc3BsYW50YXRpb24gCmBgYHtyIGJveF9wbG90X29mX2JlbmVmaXRzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPSBGQUxTRX0KZml2ZV95cl9ieV9zdGF0dXMgPC0gcG9wX3R4X2h6ICU+JSAKICBncm91cF9ieSh0aHJlZV9zdGF0dXMpICU+JQogIHN1bW1hcmlzZSgKICAgIG51bWJlciA9IG4oKSwgCiAgICBtZWRpYW4gPSAxMDAqbWVkaWFuKGJlbmVmaXQsIG5hLnJtID0gVFJVRSksCiAgICB1cHBlcl9JUVIgPSAxMDAqcXVhbnRpbGUoYmVuZWZpdCwgcHJvYnMgPSAwLjc1LCBuYS5ybSA9IFRSVUUpLAogICAgbG93ZXJfSVFSID0gMTAwKnF1YW50aWxlKGJlbmVmaXQsIHByb2JzID0gMC4yNSwgbmEucm0gPSBUUlVFKSwKICAgIG1lYW4gPSAxMDAqbWVhbihiZW5lZml0LCBuYS5ybSA9IFRSVUUpLAogICAgbWVhbl93YWl0bGlzdCA9IDEwMCptZWFuKG1hcmdpbmFsX3dhaXRzLCBuYS5ybSA9IFRSVUUpLAogICAgbWVhbl9wb3N0ID0gMTAwKm1lYW4obWFyZ2luYWxfcG9zdHMsIG5hLnJtID0gVFJVRSkKICApCgpmaXZlX3lyX2J5X3N0YXR1cwoKCgp0aHJlZV9ib3ggPC0gZ2dwbG90KGRhdGEgPSBwb3BfdHhfaHogJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHhfbGFiZWxzID0gY2FzZV93aGVuKAogICAgICAgICAgICAgICAgdGhyZWVfc3RhdHVzID09ICJTdGF0dXMgMUEiIH4gcGFzdGUwKCJTdGF0dXMgMUFcbk4gPSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hXzIoZmlsdGVyKGZpdmVfeXJfYnlfc3RhdHVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlZV9zdGF0dXMgPT0gIlN0YXR1cyAxQSIpJG51bWJlcikpLAogICAgICAgICAgICAgICAgdGhyZWVfc3RhdHVzID09ICJTdGF0dXMgMUIiIH4gcGFzdGUwKCJTdGF0dXMgMUJcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3N0YXR1cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocmVlX3N0YXR1cyA9PSAiU3RhdHVzIDFCIikkbnVtYmVyKSksCiAgICAgICAgICAgICAgICB0aHJlZV9zdGF0dXMgPT0gIlN0YXR1cyAyIiB+IHBhc3RlMCgiU3RhdHVzIDJcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWFfMihmaWx0ZXIoZml2ZV95cl9ieV9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZWVfc3RhdHVzID09ICJTdGF0dXMgMiIpJG51bWJlcikpCiAgICAgICAgICAgICAgICAgICAgICApKSwgCiAgYWVzKHkgPSAxMDAqYmVuZWZpdCwgeD14X2xhYmVscywgY29sb3IgPSB0aHJlZV9zdGF0dXMsIGZpbGwgPSB0aHJlZV9zdGF0dXMpKSArIAogIGdlb21fZG90cGxvdChiaW5heGlzID0gInkiLCAKICAgICAgICAgICAgICAgc3RhY2tkaXI9J2NlbnRlcicsIAogICAgICAgICAgICAgICBiaW53aWR0aCA9ICAxLCBkb3RzaXplID0gIDAuMiwgc3RhY2tyYXRpbyA9IC41KSArIAogIGd1aWRlcyhjb2xvcj1GQUxTRSwgZmlsbCA9IEZBTFNFKSArCiAgbGFicyh5ID0gIkFic29sdXRlIDUteWVhciBzdXJ2aXZhbCBiZW5lZml0ICglKSIsIGZpbGwgPSAiIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC01LCAxMDApKSArIAogIHRoZW1lX2ZldygpICsgCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBleHBhbmRfc2NhbGUoIG11bHQgPSBjKDAuNSwgMC4yKSkpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgZGlyZWN0aW9uID0gLTEpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBkaXJlY3Rpb24gPSAtMSkgKwogIHN0YXRfYm94cGxvdChhZXMoeCA9IHhfbGFiZWxzLCB5ID0gMTAwKmJlbmVmaXQpLCAKICAgICAgICAgICAgICAgZ2VvbSA9ICJlcnJvcmJhciIsIAogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICB3aWR0aCA9IDAuMjUsIGx3ZD0wLjc1KSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0geF9sYWJlbHMsIHkgPSAxMDAqYmVuZWZpdCksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAsIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgCiAgICAgICAgICAgICAgIHdpZHRoID0gMC41LCBsd2Q9MC43NSwgZmF0dGVuID0gMS41KQoKdGhyZWVfYm94CgpnZ3NhdmUoImZpZ180QS5lcHMiLCBwbG90ID0gdGhyZWVfYm94LCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYApEb3QgYW5kIGJveCBwbG90cyBvZiBlc3RpbWF0ZWQgZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgYXNzb2NpYXRlZCB3aXRoIGhlYXJ0IHRyYW5zcGxhbnRhdGlvbiBmb3IgYWR1bHQgcmVjaXBpZW50cyBieSBTdGF0dXMgYXQgdHJhbnNwbGFudGF0aW9uIGJldHdlZW4gMjAwNi0yMDE1LiBUaGVyZSB3ZXJlIDExLDIyNyBTdGF0dXMgMUEgcmVjaXBpZW50cyB3aXRoIG1lZGlhbiBiZW5lZml0IGZyb20gdHJhbnNwbGFudCBvZiA1OSUsIFtJUVIgNTQtIDYyJV0uIFRoZXJlIHdlcmUgNywyNTAgU3RhdHVzIDFCIHJlY2lwaWVudHMgd2l0aCBtZWRpYW4gYmVuZWZpdCBmcm9tIHRyYW5zcGxhbnQgb2YgMjclLCBbSVFSIDIzLSAzMSVdLiBJbiBhZGRpdGlvbiwgdGhlcmUgd2VyZSBvbmx5IDEsMzM4IFN0YXR1cyAyIHJlY2lwaWVudHMgd2l0aCBtZWRpYW4gYmVuZWZpdCBmcm9tIHRyYW5zcGxhbnQgb2YgMTQlLCBbSVFSIDEwLSAxNyVdLiBXaXRoaW4gcHJpb3JpdHkgU3RhdHVzIGdyb3VwcywgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBpbiB0aGUgZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgYXNzb2NpYXRlZCB3aXRoIHRyYW5zcGxhbnQgd2FzIDUuNSUgd2l0aCB0aGUgbWFqb3JpdHkgKDc2JSkgb2YgdGhlIHZhcmlhdGlvbiBhbW9uZ3N0IHJlY2lwaWVudHMgYXR0cmlidXRhYmxlIHRvIGNlbnRlci1sZXZlbCBlZmZlY3RzIGFuZCB0aGUgcmVtYWluaW5nIDI0JSBhdHRyaWJ1dGFibGUgdG8gdmFyaWF0aW9uIGluIHRyYW5zcGxhbnQgeWVhciwgd2FpdGluZyB0aW1lLCBkb25vciBxdWFsaXR5IGFuZCBpc2NoZW1pYyB0aW1lLgoKXHBhZ2VicmVhawoKCiMjIEZpZ3VyZSA0QjogRml2ZS15ZWFyIFN1cnZpdmFsIEJlbmVmaXQgQXNzb2NpYXRlZCB3aXRoIEhlYXJ0IFRyYW5zcGxhbnRhdGlvbiBieSBTaXgtc3RhdHVzIGF0IFRyYW5zcGxhbnRhdGlvbgpgYGB7ciA1Yl9yZXZpc2VkLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPSBGQUxTRX0KCgpsaW5lX3RoaWNrbmVzcyA8LSAwLjU1CmZhdHRlbl9sZXZlbCA8LSAxLjUKCmZpdmVfeXJfYnlfc2l4X3N0YXR1cyA8LSBwb3BfdHhfaHpfNl9zdGF0ICU+JQogIGdyb3VwX2J5KHNpeF9zdGF0dXMpICU+JQogIHN1bW1hcmlzZSgKICAgIG51bWJlciA9IG4oKSwgCiAgICBtZWRpYW4gPSAxMDAqbWVkaWFuKGJlbmVmaXRfNiwgbmEucm0gPSBUUlVFKSwKICAgIHVwcGVyX0lRUiA9IDEwMCpxdWFudGlsZShiZW5lZml0XzYsIHByb2JzID0gMC43NSwgbmEucm0gPSBUUlVFKSwKICAgIGxvd2VyX0lRUiA9IDEwMCpxdWFudGlsZShiZW5lZml0XzYsIHByb2JzID0gMC4yNSwgbmEucm0gPSBUUlVFKSwKICAgIG1lYW4gPSAxMDAqbWVhbihiZW5lZml0XzYsIG5hLnJtID0gVFJVRSksCiAgICBtZWFuX3dhaXRsaXN0ID0gMTAwKm1lYW4obWFyZ2luYWxfd2FpdHNfNl9zdGF0LCBuYS5ybSA9IFRSVUUpLAogICAgbWVhbl9wb3N0ID0gMTAwKm1lYW4obWFyZ2luYWxfcG9zdHNfNl9zdGF0LCBuYS5ybSA9IFRSVUUpCiAgKQoKCgpnMSA8LSBnZ3Bsb3QocG9wX3R4X2h6XzZfc3RhdCAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc2l4X3N0YXR1cyA9PSAxKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoc2l4X3N0YXR1cyA9IHBhc3RlMCgiU3RhdHVzIDFcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hXzIoZmlsdGVyKGZpdmVfeXJfYnlfc2l4X3N0YXR1cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSAxKSRudW1iZXIpKSkpICsgCiAgZ2VvbV9kb3RwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYpLAogICAgICAgICAgICAgICBjb2xvciA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgzLCAiU2V0MSIpW1szXV0sCiAgICAgICAgICAgICAgIGZpbGwgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMywgIlNldDEiKVtbM11dLAogICAgICAgICAgICAgICBiaW5heGlzID0gInkiLCBzdGFja2RpciA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICAgbWV0aG9kPSJkb3RkZW5zaXR5Iiwgc3RhY2tncm91cHMgPSBULCBiaW5wb3NpdGlvbnM9ImFsbCIsIAogICAgICAgICAgICAgICBiaW53aWR0aCA9ICAxLCBkb3RzaXplID0gIDAuMiwgc3RhY2tyYXRpbyA9IC41KSArCiAgICB0aGVtZV9mZXcoKSArdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3I9ImJsYWNrIiwgc2l6ZSA9IDAuMjUpLAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigwLC00LDAsMiksCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJBYnNvbHV0ZSA1LXllYXIgc3Vydml2YWwgYmVuZWZpdCAoJSkiLCBsaW1pdHMgPSBjKC01LCAxMDApKSArCiAgc3RhdF9ib3hwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYpLCAgCiAgICAgICAgICAgICAgIGdlb20gPSAiZXJyb3JiYXIiLCBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICB3aWR0aCA9IDAuMjUsIGx3ZD1saW5lX3RoaWNrbmVzcykgKyAKICBnZW9tX2JveHBsb3QoYWVzKHggPSBzaXhfc3RhdHVzLCB5ID0gMTAwKmJlbmVmaXRfNiksIAogICAgICAgICAgICAgICBmaWxsID0gImdyYXkiLCBhbHBoYSA9IDAsIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGggPSAwLjUsIAogICAgICAgICAgICAgICBsd2Q9bGluZV90aGlja25lc3MsIGZhdHRlbiA9IGZhdHRlbl9sZXZlbCkgCgoKZm9yIChpIGluIGMoMiwzKSl7CiAgYXNzaWduKHBhc3RlMCgiZyIsIGkpLCBnZ3Bsb3QocG9wX3R4X2h6XzZfc3RhdCAlPiUKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoc2l4X3N0YXR1cyA9PSBpKSAlPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUoc2l4X3N0YXR1cyA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMSB+cGFzdGUwKCJTdGF0dXMgMVxuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSAxKSRudW1iZXIpKSwKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMiB+cGFzdGUwKCJTdGF0dXMgMlxuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSAyKSRudW1iZXIpKSwKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMyB+cGFzdGUwKCJTdGF0dXMgM1xuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSAzKSRudW1iZXIpKSwKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gNCB+cGFzdGUwKCJTdGF0dXMgNFxuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSA0KSRudW1iZXIpKSwKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gNiB+cGFzdGUwKCJTdGF0dXMgNlxuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSA2KSRudW1iZXIpKQogICAgICAgICAgICAgICAgICAgICAgKSkpICsgCiAgZ2VvbV9kb3RwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYpLAogICAgICAgICAgICAgICBjb2xvciA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCgzLCAiU2V0MSIpW1szXV0sCiAgICAgICAgICAgICAgIGZpbGwgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMywgIlNldDEiKVtbM11dLAogICAgICAgICAgICAgICBiaW5heGlzID0gInkiLCBzdGFja2RpciA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICAgbWV0aG9kPSJkb3RkZW5zaXR5Iiwgc3RhY2tncm91cHMgPSBULCBiaW5wb3NpdGlvbnM9ImFsbCIsIAogICAgICAgICAgICAgICBiaW53aWR0aCA9ICAxLCBkb3RzaXplID0gIDAuMiwgc3RhY2tyYXRpbyA9IC41KSArCiAgICBsYWJzKGZpbGwgPSAiIiwgY29sb3IgPSAiIikgKyAKICAgIHRoZW1lX2ZldygpICt0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSAgZWxlbWVudF9saW5lKGNvbG9yPSJibGFjayIsIHNpemUgPSAwLjI1KSwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwtNCwwLC00KSwKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAwLjI1KSkrIAogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNSwgMTAwKSkgKwogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgZGlyZWN0aW9uID0gMSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgZGlyZWN0aW9uID0gMSkgKwogIHN0YXRfYm94cGxvdChhZXMoeCA9IHNpeF9zdGF0dXMsIHkgPSAxMDAqYmVuZWZpdF82KSwgIAogICAgICAgICAgICAgICBnZW9tID0gImVycm9yYmFyIiwgY29sb3IgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgd2lkdGggPSAwLjI1LCBsd2Q9bGluZV90aGlja25lc3MpICsgCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYpLCAKICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5IiwgYWxwaGEgPSAwLCBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICBsd2Q9bGluZV90aGlja25lc3MsIGZhdHRlbiA9IGZhdHRlbl9sZXZlbCkgCiAgKQp9CgoKZm9yIChpIGluIGMoNCwgNikpewogIGFzc2lnbihwYXN0ZTAoImciLCBpKSwgZ2dwbG90KHBvcF90eF9oel82X3N0YXQgJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHNpeF9zdGF0dXMgPT0gaSkgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHNpeF9zdGF0dXMgPSBjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgICAgICBzaXhfc3RhdHVzID09IDEgfnBhc3RlMCgiU3RhdHVzIDFcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWFfMihmaWx0ZXIoZml2ZV95cl9ieV9zaXhfc3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMSkkbnVtYmVyKSksCiAgICAgICAgICAgICAgICAgICAgICBzaXhfc3RhdHVzID09IDIgfnBhc3RlMCgiU3RhdHVzIDJcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWFfMihmaWx0ZXIoZml2ZV95cl9ieV9zaXhfc3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMikkbnVtYmVyKSksCiAgICAgICAgICAgICAgICAgICAgICBzaXhfc3RhdHVzID09IDMgfnBhc3RlMCgiU3RhdHVzIDNcbk4gPSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWFfMihmaWx0ZXIoZml2ZV95cl9ieV9zaXhfc3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gMykkbnVtYmVyKSksCiAgICAgICAgICAgICAgICAgICAgICBzaXhfc3RhdHVzID09IDQgfnBhc3RlMCgiU3RhdHVzIDRcbk4gPSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSA0KSRudW1iZXIpKSwKICAgICAgICAgICAgICAgICAgICAgIHNpeF9zdGF0dXMgPT0gNiB+cGFzdGUwKCJTdGF0dXMgNlxuTiA9IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l4X3N0YXR1cyA9PSA2KSRudW1iZXIpKQogICAgICAgICAgICAgICAgICAgICAgKSkpICsgCiAgZ2VvbV9kb3RwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYsIGNvbG9yID0gdGhyZWVfc3RhdHVzLCBmaWxsPXRocmVlX3N0YXR1cyksCiAgICAgICAgICAgICAgIGJpbmF4aXMgPSAieSIsIHN0YWNrZGlyID0gImNlbnRlciIsIAogICAgICAgICAgICAgICBtZXRob2Q9ImRvdGRlbnNpdHkiLCBzdGFja2dyb3VwcyA9IFQsIGJpbnBvc2l0aW9ucz0iYWxsIiwgCiAgICAgICAgICAgICAgIGJpbndpZHRoID0gIDEsIGRvdHNpemUgPSAgMC4yLCBzdGFja3JhdGlvID0gLjUpICsKICAgIGxhYnMoZmlsbCA9ICJTdGF0dXMgaW4gMyB0aWVyIHN5c3RlbToiLCBjb2xvciA9ICJTdGF0dXMgaW4gMyB0aWVyIHN5c3RlbToiKSArIAogICAgdGhlbWVfZmV3KCkgK3RoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgICAgICAgIGF4aXMubGluZSA9ICBlbGVtZW50X2xpbmUoY29sb3I9ImJsYWNrIiwgc2l6ZSA9IDAuMjUpLAogICAgICAgICAgICAgICAgICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTEpLAogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTExKSwKICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDAsLTQsMCwtNCksCiAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSkpKyAKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTUsIDEwMCkpICsKICAgICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIGRpcmVjdGlvbiA9IC0xKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBkaXJlY3Rpb24gPSAtMSkgKwogIHN0YXRfYm94cGxvdChhZXMoeCA9IHNpeF9zdGF0dXMsIHkgPSAxMDAqYmVuZWZpdF82KSwgIAogICAgICAgICAgICAgICBnZW9tID0gImVycm9yYmFyIiwgY29sb3IgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgd2lkdGggPSAwLjI1LCBsd2Q9bGluZV90aGlja25lc3MpICsgCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gc2l4X3N0YXR1cywgeSA9IDEwMCpiZW5lZml0XzYpLCAKICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5IiwgYWxwaGEgPSAwLCAKICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBvdXRsaWVyLnNoYXBlID0gTkEsIAogICAgICAgICAgICAgICB3aWR0aCA9IDAuNSwgbHdkPWxpbmVfdGhpY2tuZXNzLCBmYXR0ZW4gPSBmYXR0ZW5fbGV2ZWwpCiAgKQp9CgpteWxlZ2VuZCA8LSBnX2xlZ2VuZChnNCkKCgoKRmlnXzRCIDwtIGdyaWQuYXJyYW5nZSgKICBhcnJhbmdlR3JvYihnMSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAwLjI1KSksCiAgICAgICAgICAgICAgZzIgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpKSwKICAgICAgICAgICAgICBnMyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSkpLAogICAgICAgICAgICAgIGc0ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheSIsIHNpemUgPSAwLjI1KSksCiAgICAgICAgICAgICAgZzYgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3c9MSwgd2lkdGhzID0gYygwLjUsIDAuMywgMC43LCAxLjIsIDAuOCkpLAogICAgICAgICAgICAgICAgICAgICAgbXlsZWdlbmQsIAogICAgICAgICAgICAgbnJvdz0yLGhlaWdodHM9YygxMCwgMi4yKSkgCgpnZ3NhdmUoImZpZ180Qi5lcHMiLCBwbG90ID0gRmlnXzRCLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQpgYGAKCgoKRG90IGFuZCBib3ggcGxvdCBvZiBlc3RpbWF0ZWQgZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgYXNzb2NpYXRlZCB3aXRoIGhlYXJ0IHRyYW5zcGxhbnRhdGlvbiBmb3IgYWR1bHQgcmVjaXBpZW50cyBieSBwcm9qZWN0ZWQgc2l4LXN0YXR1cyBhdCB0cmFuc3BsYW50YXRpb24gYmV0d2VlbiAyMDA2LTIwMTUuIERvdCBjb2xvciBjb3JyZXNwb25kcyB0byB0aHJlZS1zdGF0dXMgYXQgdHJhbnNwbGFudCwgeC1heGlzIGNvcnJlc3BvbmRzIHRvIHJlLWFzc2lnbmVkIHNpeC10aWVyIFN0YXR1cy4gVGhlcmUgd291bGQgaGF2ZSBiZWVuIDI1NSBTdGF0dXMgMSByZWNpcGllbnRzIHdpdGggbWVkaWFuIGJlbmVmaXQgZnJvbSB0cmFuc3BsYW50IG9mIDY5JSwgW0lRUiA2NS0gNzElXSwgMSwyNTQgU3RhdHVzIDIgcmVjaXBpZW50cyB3aXRoIG1lZGlhbiBiZW5lZml0IGZyb20gdHJhbnNwbGFudCBvZiA2NSUsIFtJUVIgNjEtIDY3JV0sIDYsMjU1IFN0YXR1cyAzIHJlY2lwaWVudHMgd2l0aCBtZWRpYW4gYmVuZWZpdCBmcm9tIHRyYW5zcGxhbnQgb2YgNDklLCBbSVFSIDQ2LSA1MyVdLCAxMSwwMDAgU3RhdHVzIDQgcmVjaXBpZW50cyB3aXRoIG1lZGlhbiBiZW5lZml0IGZyb20gdHJhbnNwbGFudCBvZiAyOCUsIFtJUVIgMjQtIDMxJV0sIGFuZCAxLDA1MSBTdGF0dXMgNiByZWNpcGllbnRzIHdpdGggbWVkaWFuIGJlbmVmaXQgZnJvbSB0cmFuc3BsYW50IG9mIDE0JSwgW0lRUiAxMC0gMTclXS4gV2hpc2tlcnMgcmVwcmVzZW50IHNtYWxsZXN0IGFuZCBsYXJnZXN0IG9ic2VydmF0aW9ucyB3aXRoaW4gMS41IHRpbWVzIHRoZSBJUVIgb2YgdGhlIGhpbmdlcywgcG9pbnRzIHJlcHJlc2VudCBvdXRsaWVycyBiZXlvbmQgdGhpcyByYW5nZS4gV2hlbiByZS1jbGFzc2lmeWluZyByZWNpcGllbnRzIGZyb20gMjAwNi0yMDE1IGJhc2VkIG9uIG5ldyBTdGF0dXMgMS02IHN5c3RlbSwgNiwyNTUgKDU2JSkgU3RhdHVzIDFBIHJlY2lwaWVudHMgbWV0IFN0YXR1cyAzIGNyaXRpZXJpYSwgMSwyNTQgU3RhdHVzIDIgY3JpdGllcmlhICgxMSUpIGFuZCAyNTUgbWV0IFN0YXR1cyAxIGNyaXRlcmlhICgyJSkuIEEgdG90YWwgb2YgMyw0NjIgKDMxJSkgb2YgU3RhdHVzIDFBIHJlY2lwaWVudHMgd291bGQgaGF2ZSBiZWVuIGRvd25ncmFkZWQgdG8gU3RhdHVzIDQgYmVjYXVzZSBvZiB2aW9sYXRpb24gb2YgdGhlIGNhcmRpb2dlbmljIHNob2NrIHJlcXVpcmVtZW50IGF0IHRoZSB0aW1lIG9mIHRyYW5zcGxhbnQuIEFsbCA3LDI1MCBTdGF0dXMgMUIgcmVjaXBpZW50cyB3ZXJlIHJlLWFzc2lnbmVkIHRvIFN0YXR1cyA0LiBUd28taHVuZHJlZCBhbmQgdHdlbnR5LWVpZ2h0ICgyMiUpIGxvdyBwcmlvcml0eSBTdGF0dXMgMiAodGhyZWUtc3RhdHVzIHN5c3RlbSkgd291bGQgaGF2ZSBiZWVuIGFzc2lnbmVkIHRoZSBoaWdoZXIgU3RhdHVzIDQgYmVjYXVzZSBvZiByZXN0cmljdGl2ZSBjYXJkaW9teW9wYXRoeSwgY29uZ2VuaXRhbCBoZWFydCBkaXNlYXNlLCBoeXBlcnRyb3BoaWMgY2FyZGlvbXlvcGF0aHksIG9yIGFteWxvaWRvc2lzLiBUaGUgcmVjaXBpZW50cyBhcmUgdGhlIHNhbWUgaW4gYm90aCB0aGUgdGhyZWUtc3RhdHVzIGFuZCBzaXgtc3RhdHVzIG1vZGVscywgaG93ZXZlciwgdGhlIGluY3JlYXNlZCBudW1iZXIgb2YgdGllcnMgaW4gdGhlIHNpeC10aWVyIG1vZGVsIGFsbG93cyBmb3Igd2lkZXIgdmFyaWF0aW9uIGluIGVzdGltYXRlZCBzdXJ2aXZhbCBiZW5lZml0cy4gQ29tcGFyZWQgdG8gdGhlIHRocmVlLXN0YXR1cyBzeXN0ZW0sIHRoZSB3aXRoaW4tc3RhdHVzIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBkZWNyZWFzZWQgZnJvbSA1LjUlIHRvIDQuOSUuIFRoZSBtYWpvcml0eSAoNjYlKSBvZiB3aXRoaW4tc3RhdHVzIHZhcmlhdGlvbiBpbiBzdXJ2aXZhbCBiZW5lZml0IHdhcyBzdGlsbCBhdHRyaWJ1dGFibGUgdG8gY2VudGVycywgd2l0aCB0aGUgcmVtYWluaW5nIDM0JSBhdHRyaWJ1dGFibGUgdG8gdmFyaWF0aW9uIGluIHRyYW5zcGxhbnQgeWVhciwgd2FpdGluZyB0aW1lLCBkb25vciBxdWFsaXR5IGFuZCBpc2NoZW1pYyB0aW1lLgoKClxwYWdlYnJlYWsKCiMgVGV4dCBvZiBSZXN1bHRzIFNlY3Rpb24KCiMjIEJhc2ljIGRlbW9ncmFwaGljcwpgYGB7ciBqb2luX2NhbmRfdGhvcl9kZW1vcywgbWVzc2FnZT0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojZm9yIGVUYWJsZTQKY2FuZF90aG9yIDwtIGhhdmVuOjpyZWFkX3NhcygiU0FGIDIwMTggUTMvY2FuZF90aG9yLnNhczdiZGF0IiwgTlVMTCkgJT4lICAKICBoYXZlbjo6emFwX2Zvcm1hdHMoKSAlPiUgaGF2ZW46OnphcF9sYWJlbHMoKSAKCgoKaW5pdF9saXN0cyA8LSB0b19tb2RlbCAlPiUgZ3JvdXBfYnkoUFhfSUQpICU+JQogIGZpbHRlcihyb3dfbnVtYmVyKCk9PTEpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShQWF9JRCA9IGFzLm51bWVyaWMoUFhfSUQpKSAlPiVsZWZ0X2pvaW4oY2FuZF90aG9yLCBieSA9ICJQWF9JRCIpCgptZWFuX2FnZSA8LSBtZWFuKGluaXRfbGlzdHMkQ0FOX0FHRV9BVF9MSVNUSU5HKQoKcGN0X2ZlbWFsZSA8LSAxMDAqKGluaXRfbGlzdHMgJT4lIGZpbHRlcihDQU5fR0VOREVSID09ICJGIikgJT4lIG5yb3coKSkvKGluaXRfbGlzdHMgJT4lIG5yb3coKSkKYGBgCk9mIGByIGNvbW1hKGluaXRfbGlzdHMgJT4lIG5yb3coKSlgIGNhbmRpZGF0ZXMgKG1lYW4gYWdlLCBgciBjb21tYV8yKG1lYW5fYWdlKWA7IGByIGNvbW1hXzIocGN0X2ZlbWFsZSlgJSB3b21lbikgbGlzdGVkIGF0IGByIGNlbnRlcl9yZSAlPiUgbnJvdygpYCBjZW50ZXJzLgoKIyMgQmV0d2Vlbi1jZW50ZXIgVmFyaWF0aW9uIGluIHRoZSBTdXJ2aXZhbCBCZW5lZml0IEFzc29jaWF0ZWQgd2l0aCBIZWFydCBUcmFuc3BsYW50YXRpb24KCmBgYHtyIGNhbGN1bGF0ZV9lc3RpbWF0ZXN9CgojcG9wdWxhdGlvbiBlc3RpbWF0ZXMKCiMjSFIKcG9wX21lYW5faHIgPC0gY29tbWFfMihtZWFuKHBvcF90eF9oeiRocikpCnVwX0lRUl9ociA8LSBjb21tYV8yKHF1YW50aWxlKHBvcF90eF9oeiRociwgcHJvYnMgPSAwLjc1KSkKbG93X0lRUl9ociA8LSBjb21tYV8yKHF1YW50aWxlKHBvcF90eF9oeiRociwgcHJvYnMgPSAwLjI1KSkKCiMjZml2ZS15ZWFyIHN1cml2YWwgYmVuZWZpdAptZWFuX2JlbmVmaXQgPC0gY29tbWFfMigxMDAqbWVhbihwb3BfdHhfaHokYmVuZWZpdCwgbmEucm0gPSBUUlVFKSkKYmVuZWZpdF8yNSA8LSBjb21tYV8yKDEwMCpxdWFudGlsZShwb3BfdHhfaHokYmVuZWZpdCwgbmEucm0gPSBUUlVFLCBwcm9icyA9IDAuMjUpKQpiZW5lZml0Xzc1IDwtIGNvbW1hXzIoMTAwKnF1YW50aWxlKHBvcF90eF9oeiRiZW5lZml0LCBuYS5ybSA9IFRSVUUsIHByb2JzID0gMC43NSkpCgojI2ZpdmUteWVhciB3YWl0bGlzdAptZWFuX3dhaXQgPC0gY29tbWFfMigxMDAqbWVhbihwb3BfdHhfaHokbWFyZ2luYWxfd2FpdHMsIG5hLnJtID0gVFJVRSkpCndhaXRfMjUgPC0gY29tbWFfMigxMDAqcXVhbnRpbGUocG9wX3R4X2h6JG1hcmdpbmFsX3dhaXRzLCBuYS5ybSA9IFRSVUUsIHByb2JzID0gMC4yNSkpCndhaXRfNzUgPC0gY29tbWFfMigxMDAqcXVhbnRpbGUocG9wX3R4X2h6JG1hcmdpbmFsX3dhaXRzLCBuYS5ybSA9IFRSVUUsIHByb2JzID0gMC43NSkpCgoKCiMjZml2ZS15ZWFyIHBvc3QtdHJhbnNwbGFudAptZWFuX3Bvc3QgPC0gY29tbWFfMigxMDAqbWVhbihwb3BfdHhfaHokbWFyZ2luYWxfcG9zdHMsIG5hLnJtID0gVFJVRSkpCnBvc3RfMjUgPC0gY29tbWFfMigxMDAqcXVhbnRpbGUocG9wX3R4X2h6JG1hcmdpbmFsX3Bvc3RzLCBuYS5ybSA9IFRSVUUsIHByb2JzID0gMC4yNSkpCnBvc3RfNzUgPC0gY29tbWFfMigxMDAqcXVhbnRpbGUocG9wX3R4X2h6JG1hcmdpbmFsX3Bvc3RzLCBuYS5ybSA9IFRSVUUsIHByb2JzID0gMC43NSkpCmBgYAoKCkhlYXJ0IHRyYW5zcGxhbnRhdGlvbiB3YXMgYXNzb2NpYXRlZCB3aXRoIGEgbWVhbiBgciBjb21tYV8yKDEwMCooMS1hcy5udW1lcmljKHBvcF9tZWFuX2hyKSkpYCUgZGVjcmVhc2UgaW4gbW9ydGFsaXR5IHJpc2sgY29tcGFyZWQgdG8gd2FpdGluZyB3aXRob3V0IHRyYW5zcGxhbnQgKGhhemFyZCByYXRpbyBgciBwb3BfbWVhbl9ocmAsIGludGVycXVhcnRpbGUgcmFuZ2UgW0lRUl0gYHIgbG93X0lRUl9ocmAtYHIgdXBfSVFSX2hyYCkuIFRoaXMgcmlzayByZWR1Y3Rpb24gZ2VuZXJhdGVkIGEgbWVhbiBgciBtZWFuX2JlbmVmaXRgJSAoSVFSIGByIGJlbmVmaXRfMjVgLWByIGJlbmVmaXRfNzVgJSkgYWJzb2x1dGUgaW1wcm92ZW1lbnQgaW4gZml2ZS15ZWFyIHN1cnZpdmFsLCBpbmNyZWFzaW5nIGZyb20gYHIgbWVhbl93YWl0YCUgKElRUiBgciB3YWl0XzI1YC0gYHIgd2FpdF83NWAlKSB3aXRob3V0IHRyYW5zcGxhbnQgdG8gYHIgbWVhbl9wb3N0YCUgKElRUiBgciBwb3N0XzI1YC1gciBwb3N0Xzc1YCUpIHdpdGggdHJhbnNwbGFudCAoZnVsbCBtb2RlbCByZXN1bHRzIGluICoqVGFibGUgUzIqKikuCgpgYGB7ciBwZXJjZW50X2F0dHJpYnV0YWJsZV9jZW50ZXJzfQoKI0NhbGN1bGF0ZSB0aGUgd2l0aGluLXN0YXR1cyB2YXJpYXRpb24gaW4gdGhlIGJlbmVmaXQgdW5kZXIgdGhlIHRocmVlLXN0YXR1cyBzeXN0ZW0KQl9tb2RlbCA8LSBsbWVyKDEwMCpiZW5lZml0IH4gIHN0YXRfMWIgKyBzdGF0XzIgKyAoMXxjZW50ZXIpLCBkYXRhID0gcG9wX3R4X2h6KQoKCmJlbmVmaXRfdmFyIDwtIGFzLmRhdGEuZnJhbWUoVmFyQ29ycihCX21vZGVsKSkgCgpjZW50ZXJfdmFyIDwtIGZpbHRlcihiZW5lZml0X3ZhciwgZ3JwID09ICJjZW50ZXIiKSR2Y292CnJlc2lkdWFsX3ZhciA8LSBmaWx0ZXIoYmVuZWZpdF92YXIsIGdycCA9PSAiUmVzaWR1YWwiKSR2Y292Cgp0b3RfdmFyIDwtIGNlbnRlcl92YXIgKyByZXNpZHVhbF92YXIKCnNkXzMgPC0gY29tbWFfMigodG90X3ZhcileKDEvMikpCgoKcGN0X3ZhcmlhdGlvbl9jZW50ZXIgPC0gY29tbWFfMigxMDAqY2VudGVyX3Zhci90b3RfdmFyKQoKcGN0X290aGVyIDwtIGNvbW1hXzIoMTAwKigxLSBjZW50ZXJfdmFyL3RvdF92YXIpKQoKYGBgCgpgYGB7ciBjb21wYXJlX2hpZ2hfdnNfbG93X3Bvc3R9CgojZGlmZmVyZW5jZSBhbmQgOTUlIENJCgoKZGlmZl85NWNpIDwtIGZ1bmN0aW9uKHgsIHksIHc9TlVMTCl7CiAgbG0gPC0gbG0oeSB+IHgsIHdlaWdodHMgPSB3KQogIGRpZmYgPC0gY29tbWFfMihsbSRjb2VmZmljaWVudHNbWzJdXSkKICBjb25maW50KGxtLCBsZXZlbCA9IDAuOTUpCiAgbG93X2NpIDwtIGNvbW1hXzIoY29uZmludChsbSwgbGV2ZWwgPSAwLjk1KVsyLDFdKQogIHVwX2NpIDwtIGNvbW1hXzIoY29uZmludChsbSwgbGV2ZWwgPSAwLjk1KVsyLDJdKQogIAogIGlmIChsbSRjb2VmZmljaWVudHNbWzJdXT4wKXsKICAgIHJldHVybihwYXN0ZTAoIisiLCBkaWZmLCAiOyA5NSUgQ0ksICIsIGxvd19jaSwgIiB0byAiLCB1cF9jaSkpCiAgfQogIAogIHBhc3RlMChkaWZmLCAiOyA5NSUgQ0ksICIsIGxvd19jaSwgIiB0byAiLCB1cF9jaSkKfQoKCmRpZmZfOTVjaV9wY3QgPC0gZnVuY3Rpb24oeCwgeSwgdz1OVUxMKXsKICBsbSA8LSBsbSh5IH4geCwgd2VpZ2h0cyA9IHcpCiAgZGlmZiA8LSBjb21tYV8yKDEwMCpsbSRjb2VmZmljaWVudHNbWzJdXSkKICBjb25maW50KGxtLCBsZXZlbCA9IDAuOTUpCiAgbG93X2NpIDwtIGNvbW1hXzIoMTAwKmNvbmZpbnQobG0sIGxldmVsID0gMC45NSlbMiwxXSkKICB1cF9jaSA8LSBjb21tYV8yKDEwMCpjb25maW50KGxtLCBsZXZlbCA9IDAuOTUpWzIsMl0pCiAgCiAgaWYgKGxtJGNvZWZmaWNpZW50c1tbMl1dPjApewogICAgcmV0dXJuKHBhc3RlMCgiKyIsIGRpZmYsICIlOyA5NSUgQ0ksICIsIGxvd19jaSwgIiUgdG8gIiwgdXBfY2ksICIlIikpCiAgfQogIAogIHBhc3RlMChkaWZmLCAiJTsgOTUlIENJLCAiLCBsb3dfY2ksICIlIHRvICIsIHVwX2NpLCAiJSIpCn0KCgpoaWdoX2xvdyA8LSBmaXZlX3llYXJfbWVhbnMgJT4lIGZpbHRlcihzaWdfYmV0dGVyID09MSB8IHNpZ193b3JzZSA9PTEpCgpoaWdoX2ltcHJvdmVtZW50IDwtIGNvbW1hKDEwMCpzdW1tYXJ5KGxtKG1lYW5fZml2ZV95ZWFyIH4gc2lnX2JldHRlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGhpZ2hfbG93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHRzID0gaGlnaF9sb3ckbnVtX3R4KSkkY29lZmZpY2llbnRzWywxXVtbMl1dKQoKbG93X2JlbmVmaXQgPC0gZml2ZV95ZWFyX21lYW5zICU+JSBmaWx0ZXIoc2lnX3dvcnNlID09MSkKCmxvd193YWl0IDwtIGNvbW1hKDEwMCp3ZWlnaHRlZC5tZWFuKGxvd19iZW5lZml0JG1lYW5fZml2ZV95ZWFyX3dhaXQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dfYmVuZWZpdCRudW1fdHgpKQoKbG93X3Bvc3QgPC0gY29tbWEoMTAwKndlaWdodGVkLm1lYW4obG93X2JlbmVmaXQkbWVhbl9maXZlX3llYXJfcG9zdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd19iZW5lZml0JG51bV90eCkpCgpsb3dfQiA8LSBjb21tYSgxMDAqd2VpZ2h0ZWQubWVhbihsb3dfYmVuZWZpdCRtZWFuX2ZpdmVfeWVhciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd19iZW5lZml0JG51bV90eCkpCgpoaWdoX2JlbmVmaXQgPC0gZml2ZV95ZWFyX21lYW5zICU+JSBmaWx0ZXIoc2lnX2JldHRlciA9PTEpCgpoaWdoX3dhaXQgPC0gY29tbWEoMTAwKndlaWdodGVkLm1lYW4oaGlnaF9iZW5lZml0JG1lYW5fZml2ZV95ZWFyX3dhaXQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaF9iZW5lZml0JG51bV90eCkpCgpoaWdoX3Bvc3QgPC0gY29tbWEoMTAwKndlaWdodGVkLm1lYW4oaGlnaF9iZW5lZml0JG1lYW5fZml2ZV95ZWFyX3Bvc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlnaF9iZW5lZml0JG51bV90eCkpCgpoaWdoX0IgPC0gY29tbWEoMTAwKndlaWdodGVkLm1lYW4oaGlnaF9iZW5lZml0JG1lYW5fZml2ZV95ZWFyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hfYmVuZWZpdCRudW1fdHgpKQoKCnBvc3RfaGlnaF9sb3cgPC0gZGlmZl85NWNpX3BjdCh4ID0gaGlnaF9sb3ckY2VudGVyX3BlcmZvcm1hbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBoaWdoX2xvdyRtZWFuX2ZpdmVfeWVhcl9wb3N0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBoaWdoX2xvdyRudW1fdHgpCgp3YWl0X2hpZ2hfbG93IDwtIGRpZmZfOTVjaV9wY3QoeCA9IGhpZ2hfbG93JGNlbnRlcl9wZXJmb3JtYW5jZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaGlnaF9sb3ckbWVhbl9maXZlX3llYXJfd2FpdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ID0gaGlnaF9sb3ckbnVtX3R4KQoKc3Vydl9iZW5faGlnaF9sb3cgPC0gZGlmZl85NWNpX3BjdCh4ID0gaGlnaF9sb3ckY2VudGVyX3BlcmZvcm1hbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaGlnaF9sb3ckbWVhbl9maXZlX3llYXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBoaWdoX2xvdyRudW1fdHgpCgpgYGAKCkFkanVzdGVkIGZvciBTdGF0dXMsIGNhbmRpZGF0ZSByaXNrIG9mIGRlYXRoIHdpdGhvdXQgdHJhbnNwbGFudCB2YXJpZWQgZnJvbSBgciBjb21tYV8yKDEwMCooMS1taW5faW50X2V4cCkpYCUgbG93ZXIgKHJlbGF0aXZlIEhSIGByIGNvbW1hXzIobWluX2ludF9leHApYCkgdG8gYHIgY29tbWFfMigxMDAqKG1heF9pbnRfZXhwLTEpKWAlIGdyZWF0ZXIgKHJlbGF0aXZlIEhSIGByIGNvbW1hKG1heF9pbnRfZXhwKWApIHJlbGF0aXZlIHRvIHRoZSBhdmVyYWdlIGNlbnRlci4gVGhlIHJlZHVjdGlvbiBpbiBtb3J0YWxpdHkgcmlzayBmcm9tIGhlYXJ0IHRyYW5zcGxhbnRhdGlvbiBhbHNvIHZhcmllZCBzaWduaWZpY2FudGx5IGJ5IGNlbnRlciwgZnJvbSBhIG1heGltdW0gYHIgY29tbWFfMigxMDAqKDEtbWluX3R4X2V4cCkpYCUgZ3JlYXRlciByZWR1Y3Rpb24gaW4gbW9ydGFsaXR5IChyZWxhdGl2ZSBIUiBgciBjb21tYV8yKG1pbl90eF9leHApYCkgdG8gYSBtaW5pbXVtIG9mIGByIGNvbW1hXzIoMTAwKihtYXhfdHhfZXhwIC0xKSlgJSBsb3dlciByZWR1Y3Rpb24gKHJlbGF0aXZlIEhSIGByIGNvbW1hKG1heF90eF9leHApYCkgKCoqZUZpZ3VyZSAyKiopLiBJbiBjb21iaW5hdGlvbiwgdGhlc2UgY2VudGVyIGVmZmVjdHMgbGVkIHRvIHdpZGUgdmFyaWF0aW9uIGluIHRoZSBjYXNlLW1peCBhZGp1c3RlZCBzdXJ2aXZhbCBiZW5lZml0IG9mIGhlYXJ0IHRyYW5zcGxhbnRhdGlvbjogdGhlIG1lYW4gaW1wcm92ZW1lbnQgaW4gZXN0aW1hdGVkIGZpdmUteWVhciBzdXJ2aXZhbCByYW5nZWQgZnJvbSBgciBtaW5fYmVuZWZpdGAlIHRvIGByIG1heF9iZW5lZml0YCUgYnkgY2VudGVyLCBJUVIgW2ByIGxvd19xcnRfNWAlIC0gYHIgaGlnaF9xcnRfNWAlXSAoKipGaWd1cmUgMioqKS4gRm9yIGV2ZXJ5IDEwJSBkZWNyZWFzZSBpbiBleHBlY3RlZCBjYW5kaWRhdGUgZml2ZS15ZWFyIHdhaXRsaXN0IHN1cnZpdmFsIHdpdGhvdXQgdHJhbnNwbGFudGF0aW9uLCB0aGVyZSB3YXMgYSBgciBwY3RfYmVuZWZpdF9pbmNyZWFzZV9wZXJfbmVnXzEwYCUgaW5jcmVhc2UgaW4gZXN0aW1hdGVkIHN1cnZpdmFsIGJlbmVmaXQgZnJvbSBoZWFydCB0cmFuc3BsYW50ICg5NSUgQ0kgYHIgY2lfc2xvcGVfd2FpdF91cGAlIHRvIGByIGNpX3Nsb3BlX3dhaXRfbG93YCUsICoqRmlndXJlIDNBKiopLiBJbiBjb250cmFzdCwgdGhlcmUgd2FzIG5vIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCBhbmQgYmVuZWZpdCAoK2ByIHBjdF9iZW5lZml0X2luY3JlYXNlX3Bvc3RgJSwgOTUlIENJIGByIGNpX3Nsb3BlX3Bvc3RfdXBgJSB0byBgciBjaV9zbG9wZV9wb3N0X2xvd2AlKSAoKipGaWd1cmUgM0IqKikuCiAgCiAgCiAKIyMgTWVkaWNhbCBVcmdlbmN5IG9mIFJlY2lwaWVudHMgYXQgSGlnaCBhbmQgTG93IFN1cnZpdmFsIEJlbmVmaXQgQ2VudGVycwpgYGB7ciBjYW5kaWRhdGVfY2hhcmFjdGVyaXN0aWNzX2J5X2NlbnRlcl9wZXJmb3JtX3JhdGVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPSBGQUxTRX0KCiNTdGF0dXMgYXQgdHJhbnNwbGFudCBieSBjZW50ZXIgcGVyZm9ybWFuY2UKc3RhdF9ieV9iZW5lZml0IDwtIHBvcF90eF9oeiAlPiUKICBmaWx0ZXIodHggPT0xKSAlPiUKICBsZWZ0X2pvaW4oZml2ZV95ZWFyX21lYW5zICU+JSBzZWxlY3QoY2VudGVyLCBjZW50ZXJfcGVyZm9ybWFuY2UpKSAlPiUKICBmaWx0ZXIoY2VudGVyX3BlcmZvcm1hbmNlICE9ICJBdmVyYWdlIikgJT4lCiAgbXV0YXRlKGNlbnRlcl9wZXJmb3JtYW5jZSA9IGRyb3BsZXZlbHMoY2VudGVyX3BlcmZvcm1hbmNlKSwKICAgICAgICAgc2l4X3N0YXR1cyA9IGZhY3RvcihzaXhfc3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTdGF0dXMgMSIsICJTdGF0dXMgMiIsICJTdGF0dXMgMyIsICJTdGF0dXMgNCIsICJTdGF0dXMgNiIpKSkKCnBjdF8xYV9IaWdoIDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKHN0YXRfYnlfYmVuZWZpdCwgY2VudGVyX3BlcmZvcm1hbmNlID09ICJIaWdoIikkc3RhdF8xYSkpCgpwY3RfMWFfTG93IDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKHN0YXRfYnlfYmVuZWZpdCwgY2VudGVyX3BlcmZvcm1hbmNlID09ICJMb3ciKSRzdGF0XzFhKSkKCnBfMWFfYnlfY2VudGVyIDwtIGNvbW1hX3Aoc3VtbWFyeShnbG0oZGF0YSA9c3RhdF9ieV9iZW5lZml0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0XzFhIH4gY2VudGVyX3BlcmZvcm1hbmNlKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCwgbGluayA9IGxvZ2l0KSRjb2VmZmljaWVudHNbMiw0XSkKcGN0XzFhX2RpZmYgPC0gZGlmZl85NWNpX3BjdChzdGF0X2J5X2JlbmVmaXQkY2VudGVyX3BlcmZvcm1hbmNlLCBzdGF0X2J5X2JlbmVmaXQkc3RhdF8xYSwgdyA9IE5VTEwpCgoKCiNDYWxjdWxhdGUgb3ZlcnRyZWF0bWVudCBmcmFjdGlvbiBhbW9uZ3N0IG5vbi1jYXJkaW9nZW5pYyBzaG9jayBjYW5kaWRhdGVzCm92ZXJfcmF0ZXM8LSByZWNpcHMgJT4lIGxlZnRfam9pbihmaXZlX3llYXJfbWVhbnMpICU+JSAKICBmaWx0ZXIoc2l4X3N0YXR1cyA+IDMgJiBjZW50ZXJfcGVyZm9ybWFuY2UgIT0gIkF2ZXJhZ2UiKSAlPiUKICBtdXRhdGUob3Zlcl8xYSA9IGlmZWxzZSh0aHJlZV9zdGF0dXMgPT0gIlN0YXR1cyAxQSIsIDEsIDApKQoKCm92ZXJfbG93IDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKG92ZXJfcmF0ZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPT0gIkxvdyIgJiBzaXhfc3RhdHVzID4zKSRvdmVyXzFhKSkKCm92ZXJfaGlnaCA8LSBjb21tYV8yKDEwMCptZWFuKGZpbHRlcihvdmVyX3JhdGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiSGlnaCIgJiBzaXhfc3RhdHVzID4zKSRvdmVyXzFhKSkKCnBfb3ZlciA8LSBjb21tYV9wKHN1bW1hcnkoZ2xtKG92ZXJfMWEgfiBjZW50ZXJfcGVyZm9ybWFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gb3Zlcl9yYXRlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKCkpKSRjb2VmZmljaWVudHNbMiw0XSkKCm92ZXJfZGlmZiA8LSBkaWZmXzk1Y2lfcGN0KHggPSBvdmVyX3JhdGVzJGNlbnRlcl9wZXJmb3JtYW5jZSwgeSA9IG92ZXJfcmF0ZXMkb3Zlcl8xYSwgdyA9IE5VTEwpCgpzdGF0X2J5X2JlbmVmaXQgPC0gc3RhdF9ieV9iZW5lZml0ICU+JSAKICBtdXRhdGUoc3RhdF9qdXN0ID0gZmN0X3JlY29kZShzdGF0X2p1c3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgMUEgKE1DUyBjb21wbGljYXRpb24pIiA9ICJTdGF0dXMgMUEgLSAoTUNTIGNvbXBsaWNhdGlvbikiKSkKCgojU3RhdHVzIDFBIGNoYXJhY3RlcmlzdGljcwpzdGF0XzFhX3JlY2lwX3dfdHhfaHIgPC0gc3RhdF9ieV9iZW5lZml0ICU+JSAKICBmaWx0ZXIodGhyZWVfc3RhdHVzID09ICJTdGF0dXMgMUEiKSAlPiUKICBtdXRhdGUoUFhfSUQgPSBhcy5udW1lcmljKFBYX0lEKSkgJT4lIGxlZnRfam9pbih0eF9ociwgYnkgPSAiUFhfSUQiKSAlPiUKICBtdXRhdGUoR2VuZGVyID0gZmFjdG9yKENBTl9HRU5ERVIsIGxldmVscyA9IGMoIkYiLCAiTSIpKSwKICAgICAgICAgUmFjZSA9IGZhY3RvcihDQU5fUkFDRSksCiAgICAgICAgIFJhY2UgPSBmY3RfbHVtcChSYWNlLCBuID0gMyksCiAgICAgICAgUmFjZSA9IGZjdF9yZWNvZGUoUmFjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAiV2hpdGUiID0gIjgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJCbGFjayIgPSAiMTYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJIaXNwYW5pYyIgPSAiMjAwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIgPSAiT3RoZXIiKSwKICAgICAgICBEaWFnbm9zaXMgPSBjYXNlX3doZW4oCiAgICAgICAgICBDQU5fREdOPjk5OSAmIENBTl9ER048MTAwNyB+ICJEaWxhdGVkIGNhcmRpb215b3BhdGh5LCBub24taXNjaGVtaWMiLAogICAgICAgICAgQ0FOX0RHTiA9PSAxMDA3IHwgQ0FOX0RHTiA9PTEyMDAgfiAiSXNjaGVtaWMgY2FyZGlvbXlvcGF0aHkiLAogICAgICAgICAgQ0FOX0RHTj4xMDQ4ICYgQ0FOX0RHTjwgMTEwMCB+ICJSZXN0cmljdGl2ZSBjYXJkaW9teW9wYXRoeSIsCiAgICAgICAgICBUUlVFIH4gIk90aGVyIgogICAgICAgICksCiAgICAgICAgRGlhZ25vc2lzID0gZmFjdG9yKERpYWdub3NpcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkRpbGF0ZWQgY2FyZGlvbXlvcGF0aHksIG5vbi1pc2NoZW1pYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJc2NoZW1pYyBjYXJkaW9teW9wYXRoeSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZXN0cmljdGl2ZSBjYXJkaW9teW9wYXRoeSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIpKSwKICAgICAgICBEaWFiZXRlcyA9IGNhc2Vfd2hlbigKICAgICAgICAgIENBTl9ESUFCX1RZPjEgJiBDQU5fRElBQl9UWTw2IH4gIkhpc3Rvcnkgb2YgRE0iLAogICAgICAgICAgQ0FOX0RJQUJfVFkgPT0xIH4gIk5vbi1kaWFiZXRpYyIsCiAgICAgICAgICBUUlVFIH4gIlVua25vd24iCiAgICAgICAgKSwKICAgICAgICBmZW1hbGVfZ2ZyID0gaWZfZWxzZShDQU5fR0VOREVSID09ICJGIiwgMC43NDIsIDEpLAogICAgICAgIGJsYWNrX2dmciA9IGlmX2Vsc2UoUmFjZSA9PSAiQmxhY2siLCAxLjIxLCAxKSwKICAgICAgICBlR0ZSID0gMTc1KigoUkVDX0NSRUFUKV4oLTEuMTU0KSkqKFJFQ19BR0VfQVRfVFheKC0wLjIwMykpKmZlbWFsZV9nZnIqYmxhY2tfZ2ZyLAogICAgICAgIFJlbmFsX0Z1bmN0aW9uID0gY2FzZV93aGVuKAogICAgICAgICAgUkVDX0RJQUwgPT0gIlkiIH4gIkRpYWx5c2lzIiwKICAgICAgICAgIGVHRlIgPj0gNjAgfiAiR0ZSID49IDYwIG1sL21pbi8xLjczIG1eMiIsCiAgICAgICAgICBlR0ZSPj0gMzAgfiAiR0ZSID49IDMwICYgPDYwIG1sL21pbi8xLjczIG1eMiIsCiAgICAgICAgICBlR0ZSIDwgMzAgfiAiR0ZSIDwgMzAgbWwvbWluLzEuNzMgbV4yIiwKICAgICAgICAgIFRSVUUgfiAiVW5rbm93biIKICAgICAgICApLAogICAgICAgIFJlbmFsX0Z1bmN0aW9uID0gaWZfZWxzZShpcy5uYShSZW5hbF9GdW5jdGlvbik9PVRSVUUsICJVbmtub3duIiwgUmVuYWxfRnVuY3Rpb24pLAogICAgICAgIGJvZHlfc3VyZmFjZV9hcmVhID0gMC4wMDcxODQqKFJFQ19IR1RfQ00pXigwLjcyNSkqUkVDX1dHVF9LR14oMC40MjUpLAogICAgICAgIENhcmRpYWNfSW5kZXggPSBhcy5udW1lcmljKFJFQ19DQVJESUFDX09VVFBVVC9ib2R5X3N1cmZhY2VfYXJlYSksCiAgICAgICAgRnVuY3Rpb25hbF9TdGF0dXMgPSBjYXNlX3doZW4oCiAgICAgICAgICBSRUNfRlVOQ1ROX1NUQVQgPT0gMSB8IChSRUNfRlVOQ1ROX1NUQVQ+MjA2OSkgfiJMaW1pdGVkIEltcGFpcm1lbnQsIDEwLTMwJSIsCiAgICAgICAgICAoUkVDX0ZVTkNUTl9TVEFUPjIwMzkgJiBSRUNfRlVOQ1ROX1NUQVQ8MjA2MSkgfiAiTW9kZXJhdGUgSW1wYWlybWVudCwgNDAtNjAlIiwKICAgICAgICAgIChSRUNfRlVOQ1ROX1NUQVQ+MjAwMCAmIFJFQ19GVU5DVE5fU1RBVDwyMDMxKSB+ICJTZXZlcmUgSW1wYWlybWVudCwgNzAtMTAwJSIsCiAgICAgICAgICBUUlVFIH4gIlVua25vd24iCiAgICAgICAgKSwKICAgICAgICBGdW5jdGlvbmFsX1N0YXR1cyA9IGlmZWxzZShpcy5uYShGdW5jdGlvbmFsX1N0YXR1cyksICJVbmtub3duIiwgRnVuY3Rpb25hbF9TdGF0dXMpLAogICAgICAgIHNldmVyZV9pbXBhaXJtZW50ID0gaWZlbHNlKEZ1bmN0aW9uYWxfU3RhdHVzID09ICJTZXZlcmUgSW1wYWlybWVudCwgNzAtMTAwJSIsIDEsIDApLAogICAgICAgIHN0YXRfMWFfanVzdCA9IGRyb3BsZXZlbHMoc3RhdF9qdXN0KSwKICAgICAgICBhY3V0ZV9tY3MgPSBpZmVsc2Uoc3RhdF8xYV9qdXN0ID09ICJTdGF0dXMgMUEgKE1DUyBmb3Igc2hvY2spIiwgMSwgMCksCiAgICAgICAgbHZhZF9jb21wID0gaWZlbHNlKHN0YXRfMWFfanVzdCA9PSAiU3RhdHVzIDFBIChNQ1MgY29tcGxpY2F0aW9uKSIsIDEsIDApLAogICAgICAgIHBjd3BfMTUgPSBpZmVsc2UoUkVDX1BDV19NRUFOIDwgMTUsIDEsIDApLAogICAgICAgIHBjd3BfMTUgPSBpZmVsc2UoaXMubmEoUkVDX1BDV19NRUFOKSwgMCwgcGN3cF8xNSksCiAgICAgICAgIGJsb29kX3R5cGUgPSBmYWN0b3IoCiAgICAgICAgICAgY2FzZV93aGVuKAogICAgICAgICAgICAgQ0FOX0FCTyAlaW4lIGMoIkEiLCAiQTEiLCAiQTIiKSB+ICJBIiwKICAgICAgICAgICAgIENBTl9BQk8gJWluJSBjKCJBMUIiLCAiQTJCIikgfiAiQUIiLAogICAgICAgICAgICAgVFJVRSB+IENBTl9BQk8pCiAgICAgICAgICAgKSwKICAgICAgICBwYXlvciA9IGNhc2Vfd2hlbigKICAgICAgICAgIFJFQ19QUklNQVJZX1BBWSAlaW4lIGMoMyw0LDEzKSB+ICJNZWRpY2FyZSIsCiAgICAgICAgICBSRUNfUFJJTUFSWV9QQVkgPT0yIH4gIk1lZGljYWlkIiwKICAgICAgICAgIFJFQ19QUklNQVJZX1BBWSA9PSAxIH4gIlByaXZhdGUiLAogICAgICAgICAgVFJVRSB+ICJPdGhlciIKICAgICAgICApCiAgKQoKI1BDV1AgPCAxNSAKcGN0X3VuZGVyXzE1X1BDV1BfaGlnaCA8LSBjb21tYV8yKDEwMCptZWFuKGZpbHRlcihzdGF0XzFhX3JlY2lwX3dfdHhfaHIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiSGlnaCIpJHBjd3BfMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkKCgpwY3RfdW5kZXJfMTVfUENXUF9sb3cgPC0gY29tbWFfMigxMDAqbWVhbihmaWx0ZXIoc3RhdF8xYV9yZWNpcF93X3R4X2hyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPT0gIkxvdyIpJHBjd3BfMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkKCnBjd3BfMTVfZGlmZiA8LSBkaWZmXzk1Y2lfcGN0KHggPSBzdGF0XzFhX3JlY2lwX3dfdHhfaHIkY2VudGVyX3BlcmZvcm1hbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHN0YXRfMWFfcmVjaXBfd190eF9ociRwY3dwXzE1KQoKI1BDV1AgTWVhbgpwY3RfUkVDX1BDV19NRUFOX0hpZ2ggPC0gY29tbWEobWVhbihmaWx0ZXIoc3RhdF8xYV9yZWNpcF93X3R4X2hyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiSGlnaCIpJFJFQ19QQ1dfTUVBTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpCgpwY3RfUkVDX1BDV19NRUFOX0xvdyA8LSBjb21tYShtZWFuKGZpbHRlcihzdGF0XzFhX3JlY2lwX3dfdHhfaHIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPT0gIkxvdyIpJFJFQ19QQ1dfTUVBTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkKCnBjd3BfbWVhbl9kaWZmIDwtICBkaWZmXzk1Y2koeCA9IHN0YXRfMWFfcmVjaXBfd190eF9ociRjZW50ZXJfcGVyZm9ybWFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBzdGF0XzFhX3JlY2lwX3dfdHhfaHIkUkVDX1BDV19NRUFOKQoKCiNmdW5jdGlvbmFsIGltcGFpcm1lbnQKcGN0X3NldmVyZV9pbXBhaXJtZW50X0hpZ2ggPC0gY29tbWFfMigxMDAqbWVhbihmaWx0ZXIoc3RhdF8xYV9yZWNpcF93X3R4X2hyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyX3BlcmZvcm1hbmNlID09ICJIaWdoIikkc2V2ZXJlX2ltcGFpcm1lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpCgpwY3Rfc2V2ZXJlX2ltcGFpcm1lbnRfTG93IDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKHN0YXRfMWFfcmVjaXBfd190eF9ociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyX3BlcmZvcm1hbmNlID09ICJMb3ciKSRzZXZlcmVfaW1wYWlybWVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKQoKc2V2ZXJlX2ltcGFpcl9kaWZmIDwtIGRpZmZfOTVjaV9wY3QoeCA9c3RhdF8xYV9yZWNpcF93X3R4X2hyJGNlbnRlcl9wZXJmb3JtYW5jZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPXN0YXRfMWFfcmVjaXBfd190eF9ociRzZXZlcmVfaW1wYWlybWVudCkKCgojYWN1dGUgTUNTIHVzZQpwY3RfYWN1dGVfbWNzX0hpZ2ggPC0gY29tbWEoMTAwKm1lYW4oZmlsdGVyKHN0YXRfMWFfcmVjaXBfd190eF9ociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPT0gIkhpZ2giKSRhY3V0ZV9tY3MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKQoKcGN0X2FjdXRlX21jc19Mb3cgPC0gY29tbWEoMTAwKm1lYW4oZmlsdGVyKHN0YXRfMWFfcmVjaXBfd190eF9ociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiTG93IikkYWN1dGVfbWNzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKQoKCmFjdXRlX21jc19kaWZmIDwtIGRpZmZfOTVjaV9wY3QoeCA9IHN0YXRfMWFfcmVjaXBfd190eF9ociRjZW50ZXJfcGVyZm9ybWFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBzdGF0XzFhX3JlY2lwX3dfdHhfaHIkYWN1dGVfbWNzKQoKCiNMVkFEIGNvbXBsaWNhdGlvbnMKcGN0X2x2YWRfY29tcF9IaWdoIDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKHN0YXRfMWFfcmVjaXBfd190eF9ociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZW50ZXJfcGVyZm9ybWFuY2UgPT0gIkhpZ2giKSRsdmFkX2NvbXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKQoKcGN0X2x2YWRfY29tcF9Mb3cgPC0gY29tbWFfMigxMDAqbWVhbihmaWx0ZXIoc3RhdF8xYV9yZWNpcF93X3R4X2hyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyX3BlcmZvcm1hbmNlID09ICJMb3ciKSRsdmFkX2NvbXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpCgpwX2x2YWRfY29tcF9ieV9jZW50ZXIgPC0gY29tbWFfcChzdW1tYXJ5KGdsbShkYXRhID1zdGF0XzFhX3JlY2lwX3dfdHhfaHIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdmFkX2NvbXAgfiBjZW50ZXJfcGVyZm9ybWFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCkpJGNvZWZmaWNpZW50c1syLDRdKQoKbHZhZF9jb21wX2RpZmYgPC0gZGlmZl85NWNpX3BjdCh4ID0gc3RhdF8xYV9yZWNpcF93X3R4X2hyJGNlbnRlcl9wZXJmb3JtYW5jZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHN0YXRfMWFfcmVjaXBfd190eF9ociRsdmFkX2NvbXApCgojY2VudGVyIHZvbHVtZSBhbmQgYmVuZWZpdCBhc3NvY2lhdGlvbgp2b2x1bWVfYmVuZWZpdF9kaWZmIDwtIGRpZmZfOTVjaSh4ID0gZml2ZV95ZWFyX21lYW5zJG51bV90eCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAxMDAqMTAwKmZpdmVfeWVhcl9tZWFucyRtZWFuX2ZpdmVfeWVhcikKCnZvbHVtZV93YWl0X2RpZmYgPC0gZGlmZl85NWNpKHggPSBmaXZlX3llYXJfbWVhbnMkbnVtX3R4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IDEwMCoxMDAqZml2ZV95ZWFyX21lYW5zJG1lYW5fZml2ZV95ZWFyX3dhaXQpCgp2b2x1bWVfcG9zdF9kaWZmIDwtIGRpZmZfOTVjaSh4ID0gZml2ZV95ZWFyX21lYW5zJG51bV90eCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IDEwMCoxMDAqZml2ZV95ZWFyX21lYW5zJG1lYW5fZml2ZV95ZWFyX3Bvc3QpCgoKbHZhZF9yYXRlcyA8LSB0b19tb2RlbCAlPiUgCiAgZmlsdGVyKHR4ID09MSkgJT4lCiAgbGVmdF9qb2luKGNlbnRlcl9yZSAlPiUgc2VsZWN0KGNlbnRlciwgY2VudGVyX3BlcmZvcm1hbmNlKSkgJT4lIAogIGZpbHRlcihjZW50ZXJfcGVyZm9ybWFuY2UgIT0gIkF2ZXJhZ2UiKSAlPiUgCiAgbXV0YXRlKGhpZ2hfYmVuID0gaWZlbHNlKGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiSGlnaCIsIDEsIDApKQoKcGN0X2x2YWRfaGlnaCA8LSBjb21tYV8yKDEwMCptZWFuKGZpbHRlcihsdmFkX3JhdGVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlcl9wZXJmb3JtYW5jZSA9PSAiSGlnaCIpJGNmX2x2YWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpKQoKcGN0X2x2YWRfbG93IDwtIGNvbW1hXzIoMTAwKm1lYW4oZmlsdGVyKGx2YWRfcmF0ZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyX3BlcmZvcm1hbmNlID09ICJIaWdoIikkY2ZfbHZhZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkpCmBgYAoKCkNvbXBhcmVkIHRvIGF2ZXJhZ2UsIGByIG51bV9oaWdoYCBjZW50ZXJzIChgciBjb21tYV8yKDEwMCpudW1faGlnaC9ucm93KGNlbnRlcl9yZSkpYCUpIGhhZCBzaWduaWZpY2FudGx5IGhpZ2hlciBzdXJ2aXZhbCBiZW5lZml0IGFuZCBgciBudW1fbG93YCBjZW50ZXJzIChgciBjb21tYV8yKDEwMCpudW1fbG93L25yb3coY2VudGVyX3JlKSlgJSkgaGFkIHNpZ25pZmljYW50bHkgbG93ZXIgYmVuZWZpdC4gQXQgZml2ZS15ZWFycywgU3RhdHVzLWFkanVzdGVkIHBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCB3YXMgc2ltaWxhciBhdCBoaWdoIGFuZCBsb3ctYmVuZWZpdCBjZW50ZXJzIChgciBoaWdoX3Bvc3RgJSB2cy4gYHIgbG93X3Bvc3RgJSwgYHIgcG9zdF9oaWdoX2xvd2ApLiBIb3dldmVyLCBlc3RpbWF0ZWQgY2FuZGlkYXRlIHN1cnZpdmFsIHdpdGhvdXQgdHJhbnNwbGFudCB3YXMgbG93ZXIgYXQgaGlnaC1iZW5lZml0IGNlbnRlcnMgKGByIGhpZ2hfd2FpdGAlIHZzIGByIGxvd193YWl0YCUsIGByIHdhaXRfaGlnaF9sb3dgKSwgbGVhZGluZyB0byBhIGxhcmdlciBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCAoYHIgaGlnaF9CYCUgdnMgYHIgbG93X0JgJSwgYHIgc3Vydl9iZW5faGlnaF9sb3dgKS4gQ29tcGFyZWQgdG8gbG93LWJlbmVmaXQgY2VudGVycywgaGlnaC1iZW5lZml0IGNlbnRlcnMgdXNlZCBTdGF0dXMgMUEgcXVhbGlmeWluZyB0aGVyYXBpZXMgbGVzcyBmcmVxdWVudGx5ICAoYHIgcGN0XzFhX0hpZ2hgJSB2cy4gYHIgcGN0XzFhX0xvd2AlLCBgciBwY3RfMWFfZGlmZmAsICoqVGFibGUgUzMqKikgYW5kIHdlcmUgbGVzcyBsaWtlbHkgdG8gdHJlYXQgY2FuZGlkYXRlcyB3aG8gZGlkIG5vdCBtZWV0IGhlbW9keW5hbWljIHJlcXVpcmVtZW50cyBmb3IgY2FyZGlvZ2VuaWMgc2hvY2sgd2l0aCBTdGF0dXMgMUEgcXVhbGlmeWluZyBJQUJQcyBvciBoaWdoLWRvc2UgaW5vdHJvcGVzIChgciBvdmVyX2hpZ2hgJSB2cy4gYHIgb3Zlcl9sb3dgJSwgYHIgb3Zlcl9kaWZmYCkuIEF0IHRoZSB0aW1lIG9mIHRyYW5zcGxhbnQsIFN0YXR1cyAxQSBjYW5kaWRhdGVzIGF0IGhpZ2ggYmVuZWZpdCBjZW50ZXJzIGhhZCBoaWdoZXIgcHVsbW9uYXJ5IGNhcGlsbGFyeSB3ZWRnZSBwcmVzc3VyZXMgKG1lYW4gYHIgcGN0X1JFQ19QQ1dfTUVBTl9IaWdoYCB2cy4gYHIgcGN0X1JFQ19QQ1dfTUVBTl9Mb3dgIG1tSGcsIGByIHBjd3BfbWVhbl9kaWZmYCBhbmQgcGVyY2VudGFnZSBsZXNzIHRoYW4gMTUgbW1IZyBgciBwY3RfdW5kZXJfMTVfUENXUF9oaWdoYCUgdnMuIGByIHBjdF91bmRlcl8xNV9QQ1dQX2xvd2AlLCBgciBwY3dwXzE1X2RpZmZgKSwgYW5kIHdvcnNlIGZ1bmN0aW9uYWwgc3RhdHVzIChgciBwY3Rfc2V2ZXJlX2ltcGFpcm1lbnRfSGlnaGAlIHZzLiBgciBwY3Rfc2V2ZXJlX2ltcGFpcm1lbnRfTG93YCUgd2l0aCBzZXZlcmUgaW1wYWlybWVudCByZXF1aXJpbmcgY29udGludW91cyBob3NwaXRhbGl6YXRpb24sIChgciBzZXZlcmVfaW1wYWlyX2RpZmZgKSB0aGFuIGxvdy1iZW5lZml0IGNlbnRlcnMuIEhpZ2gtYmVuZWZpdCBjZW50ZXJzIHRyYW5zcGxhbnRlZCBtb3JlIHJlY2lwaWVudHMgZm9yIGFjdXRlIGhlbW9keW5hbWljIGRlY29tcGVuc2F0aW9uIHJlcXVpcmluZyBtZWNoYW5pY2FsIHN1cHBvcnQgKGByIHBjdF9hY3V0ZV9tY3NfSGlnaGAlIHZzLiBgciBwY3RfYWN1dGVfbWNzX0xvd2AlLCBgciBhY3V0ZV9tY3NfZGlmZmApIGFuZCB1c2VkIHRoZSAiZGV2aWNlLXJlbGF0ZWQgY29tcGxpY2F0aW9uIiBTdGF0dXMgMUEganVzdGlmaWNhdGlvbiBzaWduaWZpY2FudGx5IGxlc3Mgb2Z0ZW4gKGByIHBjdF9sdmFkX2NvbXBfSGlnaGAlIHZzLiBgciBwY3RfbHZhZF9jb21wX0xvd2AlLCBgciBsdmFkX2NvbXBfZGlmZmApICgqKlRhYmxlIFM0KiopLiBBdCBoaWdoIGJlbmVmaXQgY2VudGVycywgYHIgcGN0X2x2YWRfaGlnaGAlIG9mIFN0YXR1cyAxQSByZWNpcGllbnRzIGhhZCBhIEJUVCBMVkFEIGF0IHRoZSB0aW1lIG9mIHRyYW5zcGxhbnQgY29tcGFyZWQgdG9gciBwY3RfbHZhZF9sb3dgJSBvZiByZWNpcGllbnRzIGF0IGxvdyBiZW5lZml0IGNlbnRlcnMgKGByIGRpZmZfOTVjaV9wY3QobHZhZF9yYXRlcyRjZl9sdmFkLCBsdmFkX3JhdGVzJGhpZ2hfYmVuKWApLiAgQWNyb3NzIGFsbCBjZW50ZXJzLCB0cmFuc3BsYW50IHZvbHVtZSB3YXMgd2Vha2x5IGFzc29jaWF0ZWQgd2l0aCBwb3N0LXRyYW5zcGxhbnQgc3Vydml2YWwgKGByIHZvbHVtZV9wb3N0X2RpZmZgKSwgaG93ZXZlciB3YXMgbm90IGFzc29jaWF0ZWQgd2l0aCBlaXRoZXIgY2FuZGlkYXRlIHVyZ2VuY3kgKGByIHZvbHVtZV93YWl0X2RpZmZgKSBvciBzdXJ2aXZhbCBiZW5lZml0IChgciB2b2x1bWVfYmVuZWZpdF9kaWZmYCkgKCoqRmlndXJlIFM0KiopLgoKIyMgVGhlIEFzc29jaWF0aW9uIG9mIFN0YXR1cyBhbmQgU3Vydml2YWwgQmVuZWZpdCBpbiBUaHJlZSBhbmQgU2l4LVRpZXIgQWxsb2NhdGlvbiBTeXN0ZW1zCgpgYGB7ciBzdGF0dXNfc3dpdGNoZXMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiNzdGF0dXMgc3dpdGNoIHRhYmxlCnN0YXR1c19zd2l0Y2ggPC0gcG9wX3R4X2h6ICU+JSBsZWZ0X2pvaW4ocG9wX3R4X2h6XzZfc3RhdCkgJT4lCiAgZ3JvdXBfYnkoc2l4X3N0YXR1cywgdGhyZWVfc3RhdHVzKSAlPiUgY291bnQoKSAlPiUKICBzcHJlYWQoa2V5ID0gdGhyZWVfc3RhdHVzLCB2YWx1ZSA9IG4pICU+JQogIG11dGF0ZV9hbGwoZnVucyhpZmVsc2UoaXMubmEoLik9PVRSVUUsIDAsIC4pKSkKCnRvdF8xYXMgPC0gc3VtKHN0YXR1c19zd2l0Y2gkIlN0YXR1cyAxQSIpCgp0b3RfMWJzIDwtIHN1bShzdGF0dXNfc3dpdGNoJCJTdGF0dXMgMUIiKQoKdG90XzJzIDwtIHN1bShzdGF0dXNfc3dpdGNoJCJTdGF0dXMgMiIpCmBgYAoKClVuZGVyIHRoZSBwcmlvciB0aHJlZS1zdGF0dXMgaGVhcnQgYWxsb2NhdGlvbiBzeXN0ZW0sIHRoZSBtb3N0IGNvbW1vbiBTdGF0dXMgYXQgdHJhbnNwbGFudCB3YXMgMUEgKE4gPTExLDIyNywgNTclKSBhbmQgaGVhcnQgdHJhbnNwbGFudGF0aW9uIGZvciBhIFN0YXR1cyAxQSBjYW5kaWRhdGUgY29uZmVycmVkIGEgbWVhbiBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBhc3NvY2lhdGVkIHdpdGggNTglLCAoSVFSIDU0LSA2MiUpLiBTdGF0dXMgMUIgd2FzIHRoZSBuZXh0IG1vc3QgY29tbW9uIChOID0gNywyNTAsIDM3JSkgd2l0aCBhIG1lYW4gZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgYXNzb2NpYXRlZCB3aXRoIHRyYW5zcGxhbnQgb2YgMjclLCAoSVFSIDIzLSAzMSUpLiBUaGVyZSB3ZXJlIG9ubHkgMSwzMzggY2FuZGlkYXRlcyBhdCBTdGF0dXMgMiBhdCB0aGUgdGltZSBvZiB0cmFuc3BsYW50ICg3JSkgd2l0aCBtZWFuIGZpdmUteWVhciBzdXJ2aXZhbCBiZW5lZml0IGFzc29jaWF0ZWQgd2l0aCB0cmFuc3BsYW50IG9mIDE0JSwgKElRUiAxMC0gMTclKSAoRmlndXJlIDRBKS4gT3ZlcmFsbCwgd2l0aGluIGEgZ2l2ZW4gcHJpb3JpdHkgU3RhdHVzIGF0IHRyYW5zcGxhbnRhdGlvbiwgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBpbiBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCB3YXMgNS41JSB3aXRoIHRoZSBtYWpvcml0eSAoNzYlKSBvZiB0aGUgdmFyaWF0aW9uIGFtb25nc3QgcmVjaXBpZW50cyBhdHRyaWJ1dGFibGUgdG8gY2VudGVyLWxldmVsIGVmZmVjdHMgYW5kIHRoZSByZW1haW5pbmcgMjQlIGF0dHJpYnV0YWJsZSB0byB2YXJpYXRpb24gaW4gdHJhbnNwbGFudCB5ZWFyLCB3YWl0aW5nIHRpbWUsIGRvbm9yIHF1YWxpdHkgYW5kIGlzY2hlbWljIHRpbWUuCldoZW4gcmV0cm9zcGVjdGl2ZWx5IHJlLWNsYXNzaWZ5aW5nIHJlY2lwaWVudHMgZnJvbSAyMDA2LTIwMTUgYmFzZWQgb24gbmV3IFN0YXR1cyAxLTYgc3lzdGVtLCA2LDI1NSBTdGF0dXMgMUEgcmVjaXBpZW50cyBtZXQgU3RhdHVzIDMgY3JpdGVyaWEgKDU2JSksIDEsMjU0IG1ldCBTdGF0dXMgMiBjcml0ZXJpYSAoMTElKSwgYW5kIDI1NSBtZXQgU3RhdHVzIDEgY3JpdGVyaWEgKDIlKS4gQSB0b3RhbCBvZiAzLDQ2MiAoMzElKSBvZiBTdGF0dXMgMUEgcmVjaXBpZW50cyB3b3VsZCBoYXZlIGJlZW4gZG93bmdyYWRlZCB0byBTdGF0dXMgNCBiZWNhdXNlIG9mIGEgdmlvbGF0aW9uIG9mIHRoZSBjYXJkaW9nZW5pYyBzaG9jayByZXF1aXJlbWVudCBhdCB0aGUgdGltZSBvZiB0cmFuc3BsYW50LiBBbGwgNywyNTAgU3RhdHVzIDFCIHJlY2lwaWVudHMgd2VyZSByZS1hc3NpZ25lZCB0byBTdGF0dXMgNC4gVHdvLWh1bmRyZWQgYW5kIHR3ZW50eSBlaWdodCAoMjIlKSBsb3cgcHJpb3JpdHkgU3RhdHVzIDIgKHRocmVlLXN0YXR1cyBzeXN0ZW0pIHJlY2lwaWVudHMgd291bGQgaGF2ZSBiZWVuIGFzc2lnbmVkIHRvIHRoZSBoaWdoZXIgU3RhdHVzIDQgYmVjYXVzZSBvZiByZXN0cmljdGl2ZSBjYXJkaW9teW9wYXRoeSwgY29uZ2VuaXRhbCBoZWFydCBkaXNlYXNlLCBoeXBlcnRyb3BoaWMgY2FyZGlvbXlvcGF0aHksIG9yIGFteWxvaWRvc2lzLiAoZVRhYmxlNSkuIEVzdGltYXRlZCBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBhc3NvY2lhdGVkIHdpdGggdHJhbnNwbGFudCByYW5nZWQgZnJvbSBvZiA2OCUgKFN0YXR1cyAxKSB0byAxNCUgKFN0YXR1cyA2KSAoRmlndXJlIDRCKS4KQ29tcGFyZWQgdG8gdGhlIHRocmVlLXN0YXR1cyBzeXN0ZW0sIHRoZSB3aXRoaW4tc3RhdHVzIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBkZWNyZWFzZWQgZnJvbSA1LjUlIHRvIDQuOSUgYnV0IHRoZSBtYWpvcml0eSAoNjYlKSB3YXMgc3RpbGwgYXR0cmlidXRhYmxlIHRvIGNlbnRlcnMuIFRoZSBiZXR3ZWVuLWNlbnRlciB2YXJpYW5jZSBpbiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiB0cmFuc3BsYW50IG9uIHRoZSBsb2cgaGF6YXJkIHJhdGlvIHNjYWxlIHRyYW5zcGxhbnQgZGVjcmVhc2VkIGZyb20gMC4xNjEgdG8gMC4xMTUsIGNvcnJlc3BvbmRpbmcgdG8gYSByZWR1Y3Rpb24gaW4gdGhlIGJldHdlZW4tY2VudGVyIHZhcmlhbmNlIG9mIGFic29sdXRlIGZpdmUteWVhciBzdXJ2aXZhbCBiZW5lZml0IGZyb20gMjMlIHRvIDE2JS4gKGVUYWJsZTYpLgoKCgoKCmBgYHtyIHBjdF92YXJpYXRpb25fY2VudGVyX3VuZGVyX3NpeF9zdGF0fQoKI1ZhcmlhdGlvbiBpbiBsb2cgaGF6YXJkIG9mIHRyYW5zcGxhbnQgaW4gdGhyZWUgYW5kIHNpeC1zdGF0dXMgbW9kZWxzCnZhcl90eF8zX3N0YXQgPC0gVmFyQ29ycih0aHJlZV9zdGF0dXMpJGNlbnRlclsyLDJdCgp2YXJfdHhfNl9zdGF0IDwtIFZhckNvcnIoc2l4X3N0YXR1cykkY2VudGVyWzIsMl0KCiN3aXRoaW4tc3RhdHVzIHZhcmlhdGlvbiBpbiB0aGUgZml2ZS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgdW5kZXIgdGhlIHNpeC1zdGF0dXMgc3lzdGVtCkJfbW9kZWxfNiA8LSBsbWVyKDEwMCpiZW5lZml0XzYgfiAgZmFjdG9yKHNpeF9zdGF0dXMpICsgKDF8Y2VudGVyKSwgZGF0YSA9IHBvcF90eF9oel82X3N0YXQpCgpiZW5lZml0X3Zhcl82IDwtIGFzLmRhdGEuZnJhbWUoVmFyQ29ycihCX21vZGVsXzYpKSAKCmNlbnRlcl92YXJfNiA8LSBmaWx0ZXIoYmVuZWZpdF92YXJfNiwgZ3JwID09ICJjZW50ZXIiKSR2Y292CnJlc2lkdWFsX3Zhcl82IDwtIGZpbHRlcihiZW5lZml0X3Zhcl82LCBncnAgPT0gIlJlc2lkdWFsIikkdmNvdgoKdG90X3Zhcl82IDwtIGNlbnRlcl92YXJfNiArIHJlc2lkdWFsX3Zhcl82CgpzZF82IDwtIGNvbW1hXzIoKHRvdF92YXJfNileKDEvMikpCiAgCnBjdF92YXJpYXRpb25fY2VudGVyXzYgPC0gY29tbWFfMigxMDAqY2VudGVyX3Zhcl82L3RvdF92YXJfNikKCnBjdF9vdGhlcl82IDwtIGNvbW1hXzIoMTAwKigxLSBjZW50ZXJfdmFyXzYvdG90X3Zhcl82KSkKCmBgYAoKV2hlbiByZS1jbGFzc2lmeWluZyByZWNpcGllbnRzIGZyb20gMjAwNi0yMDE1IGJhc2VkIG9uIG5ldyBTdGF0dXMgMS02IHN5c3RlbSwgdGhlIG1ham9yaXR5IChgciBjb21tYV8yKDEwMCpmaWx0ZXIoc3RhdHVzX3N3aXRjaCwgc2l4X3N0YXR1cyA9PTMpJCJTdGF0dXMgMUEiL3RvdF8xYXMpYCUpIG9mIFN0YXR1cyAxQSByZWNpcGllbnRzIHdvdWxkIGhhdmUgYmVlbiBTdGF0dXMgMywgd2l0aCBhIHNtYWxsZXIgZ3JvdXAgcXVhbGlmeWluZyBmb3IgU3RhdHVzIDIgKGByIGNvbW1hXzEoMTAwKmZpbHRlcihzdGF0dXNfc3dpdGNoLCBzaXhfc3RhdHVzID09MikkIlN0YXR1cyAxQSIvdG90XzFhcylgJSkgYW5kIHZlcnkgZmV3IG1lZXRpbmcgU3RhdHVzIDEgY3JpdGVyaWEgKGByIGNvbW1hXzEoMTAwKmZpbHRlcihzdGF0dXNfc3dpdGNoLCBzaXhfc3RhdHVzID09MSkkIlN0YXR1cyAxQSIvdG90XzFhcylgJSkuIEEgc3Vic3RhbnRpYWwgcG9ydGlvbiAoYHIgY29tbWFfMigxMDAqZmlsdGVyKHN0YXR1c19zd2l0Y2gsIHNpeF9zdGF0dXMgPT00KSQiU3RhdHVzIDFBIi90b3RfMWFzKWAlKSBvZiBTdGF0dXMgMUEgY2FuZGlkYXRlcyB3b3VsZCBoYXZlIGJlZW4gZG93bmdyYWRlZCB0byBTdGF0dXMgNCBiZWNhdXNlIG9mIHZpb2xhdGlvbiBvZiB0aGUgY2FyZGlvZ2VuaWMgc2hvY2sgcmVxdWlyZW1lbnQuIEEgc21hbGwgbnVtYmVyIG9mIHJlY2lwaWVudHMgKE4gPSBgciBmaWx0ZXIoc3RhdHVzX3N3aXRjaCwgc2l4X3N0YXR1cyA9PTQpJCJTdGF0dXMgMiJgKSB3b3VsZCBoYXZlIGJlZW4gYXNzaWduZWQgYSBoaWdoZXIgc3RhdHVzIGJlY2F1c2Ugb2YgcmVzdHJpY3RpdmUgY2FyZGlvbXlvcGF0aHkgKCoqVGFibGUgUzUqKiBmb3IgZGV0YWlscykuIEZpdmUteWVhciBzdXJ2aXZhbCBiZW5lZml0IGZyb20gdHJhbnNwbGFudCByYW5nZWQgZnJvbSBvZiBgciBjb21tYV8yKGZpbHRlcihmaXZlX3lyX2J5X3NpeF9zdGF0dXMsIHNpeF9zdGF0dXMgPT0gMSkkbWVhbilgJSAoU3RhdHVzIDEpIHRvIGByIGNvbW1hXzIoZmlsdGVyKGZpdmVfeXJfYnlfc2l4X3N0YXR1cywgc2l4X3N0YXR1cyA9PSA2KSRtZWFuKWAlIChTdGF0dXMgNikgKEZpZ3VyZSA1QikuIAoKQ29tcGFyZWQgdG8gdGhlIHRocmVlLXN0YXR1cyBzeXN0ZW0sIHRoZSB3aXRoaW4tc3RhdHVzIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBmaXZlLXllYXIgc3Vydml2YWwgYmVuZWZpdCBkZWNyZWFzZWQgZnJvbSBgciBzZF8zYCUgdG8gYHIgc2RfNmAlIGJ1dCB0aGUgbWFqb3JpdHkgIChgciBwY3RfdmFyaWF0aW9uX2NlbnRlcl82YCUpIHdhcyBzdGlsbCBhdHRyaWJ1dGFibGUgdG8gY2VudGVycy4gVGhlIGJldHdlZW4tY2VudGVyIHZhcmlhbmNlIGluIHRoZSBzdXJ2aXZhbCBiZW5lZml0IG9mIHRyYW5zcGxhbnQgb24gdGhlIGxvZyBoYXphcmQgc2NhbGUgZGVjcmVhc2VkIGZyb20gYHIgY29tbWEodGhyZWVfc3RhdHVzX3ZhcilgIHRvIGByIGNvbW1hKHNpeF9zdGF0dXNfdmFyKWAgb24gbG9nIGhhemFyZCByYXRpbyBzY2FsZS4gVGhlIGJldHdlZW4tY2VudGVyIHZhcmlhbmNlIGluIGFic29sdXRlIDUteWVhciBzdXJ2aXZhbCBiZW5lZml0IGRlY3JlYXNlZCBmcm9tIGByIGNvbW1hXzIoY2VudGVyX3ZhcilgJSB0byBgciBjb21tYV8yKGNlbnRlcl92YXJfNilgJS4gICAoKipUYWJsZSBTNioqKS4KClxwYWdlYnJlYWsKCiMgU3VwcGxlbWVudAoKIyMgRmlndXJlIFMxOiBEZXRhaWxzIG9mIHByaW9yIGFuZCBjdXJyZW50IGhlYXJ0IGFsbG9jYXRpb24gc3lzdGVtCgohW10oRmlnX1MxLnBuZykKCkN1cnJlbnQgYW5kIGZ1dHVyZSBhZHVsdCBoZWFydCBhbGxvY2F0aW9uLiBTY2hlbWF0aWMgZGVwaWN0aW9uIG9mIHRoZSBzaGlmdCBmcm9tIHRoZSBjdXJyZW50IGFkdWx0IGhlYXJ0IGFsbG9jYXRpb24gc3lzdGVtIHRvIHRoZSBtb2RpZmllZCBzeXN0ZW0uIFwqIENhcmRpb2dlbmljIHNob2NrIHJlcXVpcmVtZW50IGFwcGxpZXMuIChDb25zdHJ1Y3RlZCB3aXRoIHBlcm1pc3Npb24gZGlyZWN0bHkgZnJvbSB0aGUgcG9saWN5IGRldGFpbHMgaW4gT3JnYW4gUHJvY3VyZW1lbnQgYW5kIFRyYW5zcGxhbnRhdGlvbiBOZXR3b3JrMSkuIENvbXBsZXRlIGRldGFpbCBhYm91dCBlYWNoIG9mIHRoZSBTdGF0dXMgY3JpdGVyaWEgYXJlIGF2YWlsYWJsZSBhdCBodHRwczovL29wdG4udHJhbnNwbGFudC5ocnNhLmdvdi9tZWRpYS8xMjAwL29wdG5fcG9saWNpZXMucGRmI25hbWVkZGVzdD1Qb2xpY3lfMDYuICBEaXNjaGFyZ2VhYmxlIHZzLiBub24tZGlzY2hhcmdlYWJsZSB2ZW50cmljdWxhciBzdXBwb3J0IGRldmljZXMgd2VyZSBkaXN0aW5ndWlzaGVkIHZpYSBhIGxpc3QgcHJvdmlkZWQgYnkgdGhlIFNSVFIuCgoKIyMgZUZpZ3VyZSAyOiBDZW50ZXItc3BlY2lmaWMgU3Vydml2YWwgQmVuZWZpdCBGcmFtZXdvcmsKYGBge3IgY29tYmluZWRfc3Vydml2YWxfYmVuZWZpdF9leGFtcGxlLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPSBGQUxTRX0KI1N1cnZpdmFsIGJlbmVmaXQgZnJvbSB0cmFuc3BsYW50YXRpb24gZm9yIGEgU3RhdHVzIDFBIHBhdGllbnQgCiN0cmFuc3BsYW50ZWQgYXQgYSBjZW50ZXIgd2l0aCBhIGhpZ2ggYmVuZWZpdCBmcm9tIHRyYW5zcGxhbnQKdG9wX2MgPC0gY2VudGVyX3JlICU+JSBhcnJhbmdlKC1iZW5lZml0KSAlPiUgZmlsdGVyKHJvd19udW1iZXIoKT09MSkKdG9wX2NfdHhfaHIgPC0gdG9wX2MkdHhfZXhwCnRvcF9jX3d0X3Jpc2sgPC0gdG9wX2MkaW50ZXJjZXB0X2V4cAp0b3BfYyA8LSB0b3BfYyRjZW50ZXIKCmJlc3RfY3RyX3JlY2lwcyA8LSB1bmlxdWUodG9fbW9kZWwgJT4lIGZpbHRlcihjZW50ZXIgPT0gdG9wX2MpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChQWF9JRCkpICU+JSAKICBsZWZ0X2pvaW4odG9fbW9kZWwgJT4lIHNlbGVjdChQWF9JRCwgdHgsIHN0YXRfMWEsIHRfMSwgZXJhX3R4KSAlPiUgCiAgICAgICAgICAgICAgZ3JvdXBfYnkoUFhfSUQsIHR4KSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKHR4ID09MSAmIHJvd19udW1iZXIoKSA9PTEpKSAlPiUgCiAgZmlsdGVyKGlzLm5hKHR4KSA9PSBGQUxTRSkKCmV4X3B0X3RvcCA8LSBiZXN0X2N0cl9yZWNpcHNbWzE1NiwgIlBYX0lEIl1dCgp0X3R4IDwtIGJlc3RfY3RyX3JlY2lwc1tbMTU2LCAidF8xIl1dCgpoel9nb29kIDwtIGV4cChocl90eF9paihtb2RlbCA9IHRocmVlX3N0YXR1cywgCiAgICAgICAgICAgICAgICAgICAgICAgIGRmID0gdG9fbW9kZWwsIGkgPSB0b3BfYywgaiA9IGV4X3B0X3RvcCkpCgptYXhfZnVwIDwtIG1heChiYXNlaHokdGltZSkvMzY1CgpleF9iZW5lZml0IDwtIGJlbl93YWl0X3R4KGRmID0gdG9fbW9kZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VfaHogPSBiYXNlaHosIAogICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsID0gdGhyZWVfc3RhdHVzLCBqID0gZXhfcHRfdG9wLCBpID0gdG9wX2MpCmZpdmV5cl9nb29kIDwtIGNvbW1hXzIoMTAwKihleF9iZW5lZml0W1syXV0tZXhfYmVuZWZpdFtbMV1dKSkKZml2ZXlyX2dvb2Rfd2FpdCA8LSBjb21tYV8yKDEwMCpleF9iZW5lZml0W1sxXV0pCmZpdmV5cl9nb29kX3R4IDwtIGNvbW1hXzIoMTAwKmV4X2JlbmVmaXRbWzJdXSkKCmdvb2RfcGxvdCA8LSBiX2lqKGRmID0gdG9fbW9kZWwsIGJhc2VfaHogPSBiYXNlaHosIG1vZGVsID0gdGhyZWVfc3RhdHVzLCBqID0gZXhfcHRfdG9wLCBpID0gdG9wX2MpICsgCiBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA1KjM2NSksIGJyZWFrcz0gc2VxKDAsIHRfdHggKyA1KjM2NSwgMzY1KSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPSBzZXEoMCwgMSwgMC4yKSkgKyAKICB0aGVtZV9lY29ub21pc3Rfd2hpdGUoKSArIAogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoKSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KCksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksIAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwgCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkKCgojIyMgRmlndXJlIDJCOiBTdXJ2aXZhbCBiZW5lZml0IGZyb20gdHJhbnNwbGFudGF0aW9uIGZvciBhICJTdGF0dXMgMUEiIHBhdGllbnQgCiN0cmFuc3BsYW50ZWQgYXQgYSBjZW50ZXIgd2l0aCBhIGxvd2VyIGJlbmVmaXQgZnJvbSB0cmFuc3BsYW50CndvcnN0X2MgPC0gY2VudGVyX3JlICU+JSBhcnJhbmdlKGJlbmVmaXQpICU+JSBmaWx0ZXIocm93X251bWJlcigpPT0xKQp3b3JzdF9jX3R4X2hyIDwtIHdvcnN0X2MkdHhfZXhwCndvcnN0X2Nfd3RfcmlzayA8LSB3b3JzdF9jJGludGVyY2VwdF9leHAKd29yc3RfYyA8LSB3b3JzdF9jJGNlbnRlcgoKd29yc3RfY19yZWNpcHMgPC0gdW5pcXVlKHRvX21vZGVsICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNlbnRlciA9PSB3b3JzdF9jKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChQWF9JRCkpICU+JSAKICBsZWZ0X2pvaW4odG9fbW9kZWwgJT4lIHNlbGVjdChQWF9JRCwgdHgsIHN0YXRfMWEsIHRfMSwgZXJhX3R4KSAlPiUgCiAgICAgICAgICAgICAgZ3JvdXBfYnkoUFhfSUQsIHR4KSAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKHR4ID09MSAmIHJvd19udW1iZXIoKSA9PTEpKSAlPiUgCiAgZmlsdGVyKGlzLm5hKHR4KSA9PSBGQUxTRSkKCmV4X3dvcnN0IDwtIHdvcnN0X2NfcmVjaXBzW1szMCwiUFhfSUQiXV0KCnRfdHhfd29yc3QgPC0gd29yc3RfY19yZWNpcHNbWzMwLCJ0XzEiXV0KCmV4X2JlbmVmaXRfYmFkIDwtIGJlbl93YWl0X3R4KGRmID0gdG9fbW9kZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlX2h6ID0gYmFzZWh6LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSB0aHJlZV9zdGF0dXMsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaSA9IHdvcnN0X2MsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqID0gZXhfd29yc3QpIAoKZml2ZXlyX2JhZCA8LSBjb21tYV8yKDEwMCooZXhfYmVuZWZpdF9iYWRbWzJdXS1leF9iZW5lZml0X2JhZFtbMV1dKSkKZml2ZXlyX2JhZF93YWl0IDwtIGNvbW1hXzIoMTAwKmV4X2JlbmVmaXRfYmFkW1sxXV0pCmZpdmV5cl9iYWRfdHggPC0gY29tbWFfMigxMDAqZXhfYmVuZWZpdF9iYWRbWzJdXSkKCmh6X2JhZCA8LSBleHAoaHJfdHhfaWoobW9kZWwgPSB0aHJlZV9zdGF0dXMsIGRmID0gdG9fbW9kZWwsIGkgPSB3b3JzdF9jLCBqID0gZXhfd29yc3QpKQoKCmJhZF9wbG90IDwtIGJfaWooZGYgPSB0b19tb2RlbCwgCiAgICAgICAgICAgICAgICAgYmFzZV9oeiA9IGJhc2VoeiwgCiAgICAgICAgICAgICAgICAgbW9kZWwgPSB0aHJlZV9zdGF0dXMsICAKICAgICAgICAgICAgICAgICBpID0gd29yc3RfYywgaiA9IGV4X3dvcnN0KSsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA1KjM2NSksIAogICAgICAgICAgICAgICAgICAgICBicmVha3M9IHNlcSgwLCB0X3R4X3dvcnN0ICsgNSozNjUsIDM2NSkpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz0gc2VxKDAsIDEsIDAuMikpICsgCiAgdGhlbWVfZWNvbm9taXN0X3doaXRlKCkgKyAKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KCksIGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKQoKCiNjb21iaW5lIHBsb3RzCmdfbGVnZW5kPC1mdW5jdGlvbihhLmdwbG90KXsKICB0bXAgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQoYS5ncGxvdCkpCiAgbGVnIDwtIHdoaWNoKHNhcHBseSh0bXAkZ3JvYnMsIGZ1bmN0aW9uKHgpIHgkbmFtZSkgPT0gImd1aWRlLWJveCIpCiAgbGVnZW5kIDwtIHRtcCRncm9ic1tbbGVnXV0KICByZXR1cm4obGVnZW5kKX0KCgpteWxlZ2VuZCA8LSBnX2xlZ2VuZChnb29kX3Bsb3QpCgoKZmlnXzIgPC0gZ3JpZC5hcnJhbmdlKAogICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZUdyb2IoZ29vZF9wbG90ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBiYWRfcGxvdCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBucm93PTEsIHdpZHRocyA9IGMoMSwgMC45KSksCiAgICAgICAgICAgICAgICAgICAgICBteWxlZ2VuZCwgCiAgICAgICAgICAgICBucm93PTIsaGVpZ2h0cz1jKDEwLCAyLjIpKSAKCmdnc2F2ZSgiZWZpZ18yLnBkZiIsIHBsb3QgPSBmaWdfMikKYGBgClR3byBleGFtcGxlIHN1cnZpdmFsIGJlbmVmaXQgcHJlZGljdGlvbnMgaW5jb3Jwb3JhdGluZyB0aGUgdGltaW5nIG9mIHRyYW5zcGxhbnRhdGlvbiwgY2FuZGlkYXRlIHN0YXR1cywgZG9ub3IgcXVhbGl0eSwgaXNjaGVtaWMgdGltZSwgYW5kIHllYXIgb2YgdHJhbnNwbGFudC4gCgpUaGUgaGlnaC1iZW5lZml0IGNlbnRlciAoUGFuZWwgQSkgcHJpb3JpdGl6ZXMgU3RhdHVzIDFBIGNhbmRpZGF0ZXMgYXQgaGlnaGVyIHJpc2sgb2Ygd2FpdC1saXN0IG1vcnRhbGl0eSBhbmQgdHJhbnNwbGFudGF0aW9uIGF0IHRoaXMgY2VudGVyIGxvd2VycyByaXNrIG1vcmUgdGhhbiBhdmVyYWdlLiBTcGVjaWZpY2FsbHksIGNhbmRpZGF0ZXMgbGlzdGVkIGJ5IHRoaXMgY2VudGVyIGhhdmUgYSByaXNrIG9mIGRlYXRoIGByIGNvbW1hXzIoKHRvcF9jX3d0X3Jpc2stMSkqMTAwKWAlIGhpZ2hlciB0aGFuIHRoZSBhdmVyYWdlIGNlbnRlciAocmVsYXRpdmUgSFIgYHIgY29tbWEodG9wX2Nfd3RfcmlzaylgKSBhbmQgdHJhbnNwbGFudCBsb3dlcnMgdGhlIHJpc2sgb2YgbW9ydGFsaXR5IGByIGNvbW1hXzIoMTAwKigxLXRvcF9jX3R4X2hyKSlgJSBtb3JlIHRoYW4gYXQgdGhlIGF2ZXJhZ2UgY2VudGVyIChIUiBgciBjb21tYV8yKHRvcF9jX3R4X2hyKWApLiBUaGUgY29tYmluYXRpb24gb2YgdGhlc2UgdHdvIGVmZmVjdHMgbGVhZHMgdG8gYSBsYXJnZSA1LXllYXIgc3Vydml2YWwgYmVuZWZpdCwgaW1wcm92aW5nIHN1cnZpdmFsIChjb25kaXRpb25hbCB1cG9uIHJlYWNoaW5nIHRyYW5zcGxhbnQpIGZyb20gYHIgZml2ZXlyX2dvb2Rfd2FpdGAlIHRvIGByIGZpdmV5cl9nb29kX3R4YCUgKCtgciBmaXZleXJfZ29vZGAlIGFic29sdXRlIGdhaW4pIGZvciB0aGlzIHBhcnRpY3VsYXIgU3RhdHVzIDFBIHBhdGllbnQgdHJhbnNwbGFudGVkIGFmdGVyIHdhaXRpbmcgYHIgdF90eGAgZGF5cy4KCkluIGNvbnRyYXN0LCB0aGUgcGF0aWVudHMgdHJhbnNwbGFudGVkIGF0IHRoZSBsb3ctYmVuZWZpdCBjZW50ZXIgKFBhbmVsIEIpIGFyZSBhdCBsb3dlciByaXNrIG9mIGR5aW5nIG9uIHRoZSB3YWl0bGlzdCBhdCBiYXNlbGluZSBhbmQgdHJhbnNwbGFudGF0aW9uIGF0IHRoaXMgY2VudGVyIGxvd2VycyByaXNrIGxlc3MgdGhhbiBhdmVyYWdlLiBTcGVjaWZpY2FsbHksIGNhbmRpZGF0ZXMgbGlzdGVkIGJ5IHRoaXMgY2VudGVyIGhhdmUgYSByaXNrIG9mIGRlYXRoIGByIGNvbW1hXzIoKDEtd29yc3RfY193dF9yaXNrICkqMTAwKWAlIGxvd2VyIHRoYW4gdGhlIGF2ZXJhZ2UgY2VudGVyIChIUiBgciBjb21tYV8yKHdvcnN0X2Nfd3RfcmlzaylgKSBhbmQgdHJhbnNwbGFudCBsb3dlcnMgdGhlIHJpc2sgb2YgbW9ydGFsaXR5IGByIGNvbW1hXzIoMTAwKih3b3JzdF9jX3R4X2hyLTEpKWAlIGxlc3MgdGhhbiBhdCB0aGUgYXZlcmFnZSBjZW50ZXIgKEhSIGByIGNvbW1hKHdvcnN0X2NfdHhfaHIpYCkuIERlc3BpdGUgdGhlIGZhY3QgdGhhdCB0aGUgY2FuZGlkYXRlIGhhcyB0aGUgc2FtZSBwcmlvcml0eSBTdGF0dXMgYXMgdGhlIGNhbmRpZGF0ZSBpbiBQYW5lbCBBLCB0aGUgY29tYmluYXRpb24gb2YgdGhlc2UgdHdvIGVmZmVjdHMgbGVhZHMgdG8gYSBzbWFsbGVyIDUteWVhciBzdXJ2aXZhbCBiZW5lZml0LCBpbXByb3Zpbmcgc3Vydml2YWwgZnJvbSAgYHIgZml2ZXlyX2JhZF93YWl0YCUgdG8gYHIgZml2ZXlyX2JhZF90eGAlICgrYHIgZml2ZXlyX2JhZGAlIGFic29sdXRlIGdhaW4pIGZvciB0cmFuc3BsYW50ZWQgYWZ0ZXIgd2FpdGluZyBgciB0X3R4X3dvcnN0YCBkYXlzLgoKXHBhZ2VicmVhawoKCgojIyBUYWJsZSBTMjogVGhyZWUtc3RhdHVzIGBjb3htZWAgcmVzdWx0cwpgYGB7ciB0aHJlZV9zdGF0dXNfZGlzcGxheX0KcHJpbnQodGhyZWVfc3RhdHVzLCBkaWdpdHMgPTIpCmBgYAoKIyMjIDk1JSBDb25maWRlbmNlIEludGVydmFscyBvZiBjb2VmZmljaWVudHMKYGBge3IgdGFibGVfZmVfcmVzdWx0c30KdGFibGVfZmVfcmVzdWx0cyA8LSBmdW5jdGlvbihtZV9jb3hfMSl7CiAgZmVfcmVzdWx0c190YWJsZSA8LSB0aWJibGUoY292YXJpYXRlID0gY2hhcmFjdGVyKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBsb2cgaGF6YXJkIHJhdGlvYCA9IGNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA5NSUgQ0lgID0gY2hhcmFjdGVyKCkpCiAgZmUgPC0gZml4ZWYobWVfY294XzEpCiAgdmMgPC0gdmNvdihtZV9jb3hfMSkKICBmb3IgKGkgaW4gc2VxX2Fsb25nKGZlKSl7CiAgICBuYW1lIDwtIG5hbWVzKGZlW2ldKQogICAgaHIgPC0gY29tbWEodW5uYW1lKGZlW2ldKSkKICAgIHNlIDwtIHNxcnQodmNbaSxpXSkKICAgIGNpIDwtIHBhc3RlMCgiKCIsIGNvbW1hKHVubmFtZShmZVtpXSkgLSAxLjk2KnNlKSwgCiAgICAgICAgICAgICAgICAgIiwgIiwgCiAgICAgICAgICAgICAgICAgY29tbWEodW5uYW1lKGZlW2ldKSArIDEuOTYqc2UpLCAiKSIpCiAgICBmZV9yZXN1bHRzX3RhYmxlIDwtIHJiaW5kKGZlX3Jlc3VsdHNfdGFibGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWJibGUoY292YXJpYXRlID1uYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBsb2cgaGF6YXJkIHJhdGlvYCA9IGhyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA5NSUgQ0lgID0gY2kpKQogIH0KICByZXR1cm4oZmVfcmVzdWx0c190YWJsZSkKfQoKdGFibGVfZmVfcmVzdWx0cyh0aHJlZV9zdGF0dXMpCgojd3JpdGVfY3N2KHRhYmxlX2ZlX3Jlc3VsdHModGhyZWVfc3RhdHVzKSwgInRocmVlX3N0YXR1c19maXhlZC5jc3YiKQpgYGAKCgpgYGB7ciBwbG90X3R4X2VmZmVjdF9ieV9zdGF0dXMsIGVjaG8gPSBGQUxTRX0KcGxvdF90eF9lZmZlY3RzIDwtIGZ1bmN0aW9uKG1vZGVsKXsKICB0b19wbG90IDwtIHRpYmJsZShjb3ZhcmlhdGUgPSBjaGFyYWN0ZXIoKSwgCiAgICAgICAgICAgICAgICAgICAgaGF6ID0gbnVtZXJpYygpLCAKICAgICAgICAgICAgICAgICAgICBsb3dfY2kgPSBudW1lcmljKCksIAogICAgICAgICAgICAgICAgICAgIHVwX2NpID0gbnVtZXJpYygpKQogIHZjIDwtIHZjb3YobW9kZWwpCiAgZmUgPC0gZml4ZWYobW9kZWwpCiAgdHhfMWEgPC0gIGZpeGVmKG1vZGVsKVsndHgnXQogIAogIGZvciAoaSBpbiBzZXFfYWxvbmcoZmUpKXsKICAgIG5hbWUgPC0gbmFtZXMoZmVbaV0pCiAgICBpZihncmVwbCgidHgiLCBuYW1lKSA9PSBUUlVFKXsKICAgICAgaWYgKG5hbWUgPT0gInR4Iil7CiAgICAgICAgaHIgPC0gZXhwKHVubmFtZShmZVtpXSkpCiAgICAgICAgc2UgPC0gc3FydCh2Y1tpLGldKQogICAgICAgIGxjaSA8LSBleHAodW5uYW1lKGZlW2ldKS0gMS45NipzZSkKICAgICAgICB1Y2kgPC0gZXhwKHVubmFtZShmZVtpXSkrIDEuOTYqc2UpCiAgICAgICAgdG9fcGxvdCA8LSByYmluZCh0b19wbG90LCAKICAgICAgICAgICAgICAgICAgICAgICAgIHRpYmJsZShjb3ZhcmlhdGUgPW5hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhheiA9IGhyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dfY2kgPSBsY2ksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwX2NpID0gdWNpKSkKICAgICAgfQogICAgICBlbHNlewogICAgICAgIGhyIDwtIGV4cCh1bm5hbWUoZmVbaV0pKyB0eF8xYSkKICAgICAgICBzZSA8LSBzcXJ0KHZjW2ksaV0gKyB2Y1sxLDFdICsgMiogdmNbMSxpXSkKICAgICAgICBsY2kgPC0gZXhwKHVubmFtZShmZVtpXSkrIHR4XzFhIC0gMS45NipzZSkKICAgICAgICB1Y2kgPC0gZXhwKHVubmFtZShmZVtpXSkrIHR4XzFhICsgMS45NipzZSkKICAgICAgICB0b19wbG90IDwtIHJiaW5kKHRvX3Bsb3QsIHRpYmJsZShjb3ZhcmlhdGUgPW5hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhheiA9IGhyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dfY2kgPSBsY2ksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwX2NpID0gdWNpKSkKICAgICAgfQoKICAgIH0KICB9CiAgCgogIHJldHVybih0b19wbG90KQp9CgpgYGAKCmBgYHtyIHBsb3RfdGhyZWVfc3RhdHVzLCBtZXNzYWdlPUZBTFNFfQoKdG9fcGxvdCA8LSBwbG90X3R4X2VmZmVjdHModGhyZWVfc3RhdHVzKSAlPiUgCiAgbXV0YXRlKGBQYXRpZW50IFN0YXR1c2AgPSBmYWN0b3IoY292YXJpYXRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ0eCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInR4OnN0YXRfMWIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0eDpzdGF0XzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0eF9yaXNreV9kb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImVyYV90eCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSAgYygiU3RhdHVzIDFBIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN0YXR1cyAxQiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhpZ2ggcmlzayBkb25vciAoU3RhdHVzIDFBIHJlY2lwaWVudCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVmb3JlIDIwMTAgKFN0YXR1cyAxQSByZWNpcGllbnQpIikpKSAlPiUgCiAgYXJyYW5nZShmYWN0b3IoY292YXJpYXRlLCAKICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ0eCIsInR4OnN0YXRfMWIiLCAidHg6c3RhdF8yIiwgInR4X3Jpc2t5X2RvbiIsImVyYV90eCIpKSkKCmdncGxvdChkYXRhID0gdG9fcGxvdCAlPiUgCiAgICAgICAgIGZpbHRlcighY292YXJpYXRlICVpbiUgYygidHhfcmlza3lfZG9uIiwiZXJhX3R4IikpLCAKICAgICAgIGFlcyh5ID0gYFBhdGllbnQgU3RhdHVzYCwgeCA9IGhheikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtaW4gPSBsb3dfY2ksIHhtYXggPSB1cF9jaSkpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKyAKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpLCAKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLCAwLjI1LCAwLjUsIDAuNzUsIDEpLCAgCiAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQmVuZWZpdCBoZWFydCB0cmFuc3BsYW50YXRpb24gKEhSIGZvciBEZWF0aCkiICkKCgp0eF9lc3QgPC0gY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09ICJ0eCIpJGhheikKdHhfbG93IDwtY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09ICJ0eCIpJGxvd19jaSkKdHhfdXAgPC0gY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09ICJ0eCIpJHVwX2NpKQoKCnN0YXRfMWJfZXN0IDwtIGNvbW1hXzIoZmlsdGVyKHRvX3Bsb3QsIGNvdmFyaWF0ZSA9PSAidHg6c3RhdF8xYiIpJGhheikKc3RhdF8xYl9sb3cgPC1jb21tYV8yKGZpbHRlcih0b19wbG90LCBjb3ZhcmlhdGUgPT0gInR4OnN0YXRfMWIiKSRsb3dfY2kpCnN0YXRfMWJfdXAgPC0gY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09ICJ0eDpzdGF0XzFiIikkdXBfY2kpCgoKc3RhdF8yX2VzdCA8LSBjb21tYV8yKGZpbHRlcih0b19wbG90LCBjb3ZhcmlhdGUgPT0gInR4OnN0YXRfMiIpJGhheikKc3RhdF8yX2xvdyA8LWNvbW1hXzIoZmlsdGVyKHRvX3Bsb3QsIGNvdmFyaWF0ZSA9PSAidHg6c3RhdF8yIikkbG93X2NpKQpzdGF0XzJfdXAgPC0gY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09ICJ0eDpzdGF0XzIiKSR1cF9jaSkKCmdnc2F2ZSgiSFJfdHJhbnNwbGFudF9tb2RlbF8xLnBkZiIpCgpgYGAKSGF6YXJkIHJhdGlvcyBvZiB0cmFuc3BsYW50YXRpb24gaW4gdGhlIG9sZCAzLXN0YXR1cyBzeXN0ZW0gYXQgdHJhbnNwbGFudGF0aW9uIGFzIGVzdGltYXRlZCBieSBtaXhlZC1lZmZlY3RzIG1vZGVsLCBhZGp1c3RlZCBmb3IgZG9ub3IgcmlzaywgaXNjaGVtaWMgdGltZSwgYW5kIHllYXIgb2YgdHJhbnNwbGFudCAoc2VlIHN1cHBsZW1lbnQgZm9yIGZ1bGwgbW9kZWwgcmVzdWx0cykuCgpTdGF0dXMgMUEgY2FuZGlkYXRlcyBoYWQgYSBoYXphcmQgcmF0aW8gb2YgdHJhbnNwbGFudCBgciB0eF9lc3RgICg5NSUgQ0kgYHIgdHhfbG93YC1gciB0eF91cGApLCBTdGF0dXMgMUIgY2FuZGlkYXRlcyBoYWQgYSBIUiBvZiBgciBzdGF0XzFiX2VzdGAgKDk1JSBDSSBgciBzdGF0XzFiX2xvd2AtYHIgc3RhdF8xYl91cGApIGFuZCBTdGF0dXMgMiBjYW5kaWRhdGVzIGhhZCBhIEhSIG9mIGByIHN0YXRfMl9lc3RgICg5NSUgQ0kgYHIgc3RhdF8yX2xvd2AtYHIgc3RhdF8yX3VwYCkuIAoKIyMgRmlndXJlIFMyOiBTbW9vdGhlZCBiYXNlbGluZSBoYXphcmQgZnVuY3Rpb24gZnJvbSB0aW1lIG9mIGxpc3RpbmcKYGBge3IgYmFzZWxpbmVfaGF6YXJkLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPSBGQUxTRX0KCmdncGxvdChkYXRhID0gYmFzZWh6LCBhZXMoeD10aW1lLzM2NSwgeSA9IGh6X3QpKSArIAogIGdlb21fc21vb3RoKCkgKyAKICBsYWJzKHkgPSAiSGF6YXJkIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJZZWFycyBhZnRlciBsaXN0aW5nIiwgbGltaXRzID0gYygwLCAxMiksIGJyZWFrcyA9IHNlcSgwLCAxMiwgMikpCgpnZ3NhdmUoImJhc2VfaGF6YXJkLnBkZiIpCmBgYApUaGlzIGJhc2VsaW5lIGhhemFyZCBmdW5jdGlvbiB1c2VkIHRvIGNhbGN1bGF0aW5nIHRoZSA1LXllYXIgYmVuZWZpdCB3YXMgZXN0aW1hdGVkIG5vbi1wYXJhbWV0cmljYWxseSB1c2luZyBhIGthcGxhbi1tZWllciBlc3RpbWF0ZS4gSW1tZWRpYXRlbHkgYWZ0ZXIgbGlzdGluZyBmb3IgaGVhcnQgdHJhbnNwbGFudGF0aW9uLCBjYW5kaWRhdGVzIGhhdmUgaW5jcmVhc2VkIGhhemFyZCBvZiBkZWF0aC4gTW9yZSB0aGFuIDUgeWVhcnMgYWZ0ZXIgbGlzdGluZyB0aGUgaGF6YXJkIGJlZ2lucyB0byByaXNlIGFnYWluIGR1ZSB0byBhZ2luZy4gCgoKIyNGaWd1cmUgUzM6IERpc3RyaWJ1dGlvbiBvZiBTdXJ2aXZhbCBCZW5lZml0IGF0IHRoZSBCZXN0IGFuZCBXb3JzdCBDZW50ZXIsIDIwMDYtMjAxNQpgYGB7ciBwbG90X2Jlc3Rfd29yc3RfNV95cl9zdW0sIG1lc3NhZ2U9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQpiZXN0X2NlbnRlciA8LSBwYXN0ZTAoYXMuY2hhcmFjdGVyKAogIGZpdmVfeWVhcl9tZWFuc1tmaXZlX3llYXJfbWVhbnMkbWVhbl9maXZlX3llYXIgPT1tYXgoZml2ZV95ZWFyX21lYW5zJG1lYW5fZml2ZV95ZWFyKSxdJGNlbnRlciksICIueCIpCgp3b3JzdF9jZW50ZXIgPC0gcGFzdGUwKGFzLmNoYXJhY3RlcigKICBmaXZlX3llYXJfbWVhbnNbZml2ZV95ZWFyX21lYW5zJG1lYW5fZml2ZV95ZWFyID09bWluKGZpdmVfeWVhcl9tZWFucyRtZWFuX2ZpdmVfeWVhciksXSRjZW50ZXIpLCAiLngiKQoKdG9fcGxvdCA8LSBiZW5fZml2ZV95ZWFyX29ubHkgJT4lIHNlbGVjdChiZXN0X2NlbnRlciwgd29yc3RfY2VudGVyKSAlPiUgCiAgZ2F0aGVyKGtleSA9IGNlbnRlciwgdmFsdWUgPSBmaXZlX3llYXJfYmVuZWZpdCkgJT4lIAogIG11dGF0ZShjdHIgPSBpZl9lbHNlKGNlbnRlciA9PSBiZXN0X2NlbnRlciwgIkJlc3QgQ2VudGVyIiwgIldvcnN0IENlbnRlciIpKQoKYmVzdF9jdHJfbWVhbiA8LSBjb21tYV8yKAogIDEwMCptZWFuKGZpbHRlcih0b19wbG90LCBjdHIgPT0gIkJlc3QgQ2VudGVyIikkZml2ZV95ZWFyX2JlbmVmaXQsIG5hLnJtID0gVFJVRSkpCgp3b3JzdF9jdHJfbWVhbiA8LSBjb21tYV8yKAogIDEwMCptZWFuKGZpbHRlcih0b19wbG90LCBjdHIgPT0gIldvcnN0IENlbnRlciIpJGZpdmVfeWVhcl9iZW5lZml0LCBuYS5ybSA9VFJVRSkpCgpnZ3Bsb3QodG9fcGxvdCwgYWVzKHggPSBmaXZlX3llYXJfYmVuZWZpdCoxMDAsIGZpbGwgPSBjdHIpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gIGMoLTI1LCAxMDApLCBuYW1lID0gIjUteWVhciBzdXJ2aXZhbCBiZW5lZml0ICglKSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInJlZCIpKSArIAogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKCIiKSkKCmdnc2F2ZSgiZmlnX1M0LnBkZiIpCmBgYApEaXN0cmlidXRpb24gb2YgNS15ZWFyIHN1cnZpdmFsIGJlbmVmaXQgaWYgdGhlIGJlc3QgYW5kIHdvcnN0IGNlbnRlciBoeXBvdGhldGljYWxseSBoYWQgdHJhbnNwbGFudGVkIGFsbCByZWNpcGllbnRzIGR1cmluZyB0aGUgc3R1ZHkgdGltZSBwZXJpb2QuICBUaGUgYmVzdCBjZW50ZXIgaGFkIGEgbWVhbiBmaXZlIHllYXIgc3Vydml2YWwgYmVuZWZpdCBvZiBgciBiZXN0X2N0cl9tZWFuYCUgY29tcGFyZWQgdG8gb25seSBgciB3b3JzdF9jdHJfbWVhbmAlIGF0IHRoZSBsb3dlc3QgYmVuZWZpdCBjZW50ZXIuCgojIyBUYWJsZSBTMzogU3RhdHVzIGF0IGhlYXJ0IHRyYW5zcGxhbnRhdGlvbiBieSBjZW50ZXIgbGV2ZWwgb2YgYmVuZWZpdApgYGB7ciBzdGF0dXNfYXRfdHJhbnNwbGFudF9ieV9iZW5lZml0LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPSBGQUxTRSwgcmVzdWx0cyA9ICdhc2lzJ30KdGFuZ3JhbTo6cm1kKHRhbmdyYW06OnRhbmdyYW0oImNlbnRlcl9wZXJmb3JtYW5jZSB+IHRocmVlX3N0YXR1cyArIHNpeF9zdGF0dXMiLCBzdGF0X2J5X2JlbmVmaXQsIGRpZ2l0cyA9IDMpKQpgYGAKCiMjIFRhYmxlIFM0OiBTdGF0dXMgMUEgcmVjaXBpZW50IGNoYXJhY3RlcmlzdGljcyBhdCB0aW1lIG9mIHRyYW5zcGxhbnQgYnkgY2VudGVyIGJlbmVmaXQKCmBgYHtyIHJlY2lwX2NoYXJhY3RlcmlzdGljcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cyA9ICdhc2lzJ30KI0xhYmVsIFZhcmlhYmxlcyB3aGVuIG5lY2Vzc2FyeQpIbWlzYzo6bGFiZWwoc3RhdF8xYV9yZWNpcF93X3R4X2hyJENhcmRpYWNfSW5kZXgpIDwtICJDYXJkaWFjIEluZGV4IChML21pbi9tXjIpIgpIbWlzYzo6bGFiZWwoc3RhdF8xYV9yZWNpcF93X3R4X2hyJFJFQ19QQ1dfTUVBTikgPC0gIk1lYW4gUHVsbW9uYXJ5IENhcGlsbGFyeSBXZWRnZSBQcmVzc3VyZSAobW1IZykiCgpIbWlzYzo6bGFiZWwoc3RhdF8xYV9yZWNpcF93X3R4X2hyJHN0YXRfMWFfanVzdCkgPC0gIlN0YXR1cyAxQSBKdXN0aWZpY2F0aW9uIGF0IFRyYW5zcGxhbnQiCgp0YW5ncmFtOjpybWQodGFuZ3JhbTo6dGFuZ3JhbSgiY2VudGVyX3BlcmZvcm1hbmNlIH4gYmVuZWZpdCArIG1hcmdpbmFsX3Bvc3RzICsgbWFyZ2luYWxfd2FpdHMgKyAgdF8xICsgUkVDX0FHRV9BVF9UWCArIFJFQ19CTUkgKyBHZW5kZXIgKyBSYWNlICsgRGlhZ25vc2lzICsgRGlhYmV0ZXMgKyBSZW5hbF9GdW5jdGlvbiArIEZ1bmN0aW9uYWxfU3RhdHVzICsgQ2FyZGlhY19JbmRleCArIFJFQ19QQ1dfTUVBTiArIHN0YXRfMWFfanVzdCArIHBheW9yIiwgZGF0YSA9IHN0YXRfMWFfcmVjaXBfd190eF9ocikpCmBgYApGb3IgY29udGludW91cyB2YXJpYWJsZXMsIG1lZGlhbiBhbmQgSVFScyBhcmUgcHJlc2VudGVkIGFuZCBncm91cCBjb21wYXJpc29uIHRlc3RpbmcgcC12YWx1ZXMgb2J0YWluZWQgdXNpbmcgS3J1c2thbC1XYWxsaXMuIEZvciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIG51bWJlciAoJSkgYXJlIHByZXNlbnRlZCBhbmQgZ3JvdXAgY29tcGFyaXNvbiB0ZXN0aW5nIHAtdmFsdWVzIGNhbGN1bGF0ZWQgd2l0aCBQZWFyc29uIENoaS1zcXVhcmVkIHRlc3QuIEdGUiA9IEdsb21lcnVsYXIgRmlsdHJhdGlvbiBSYXRlLCBjYWxjdWxhdGVkIGJ5IHRoZSBNb2RpZmljYXRpb24gaW4gRGlldCBpbiBSZW5hbCBEaXNlYXNlIChNRFJEKSBmb3JtdWxhLiBCb2R5IHN1cmZhY2UgYXJlYSBmb3IgY2FyZGlhYyBpbmRleCBjYWxjdWxhdGVkIHdpdGggbWV0aG9kIG9mIER1IEJvaXMuIEZ1bmN0aW9uYWwgc3RhdHVzIGlzIG9uIHRoZSBLYXJub2Zza3kgc2NhbGUuCgoKIyMgVGFibGUgUzUg4oCTIENsYXNzaWZpY2F0aW9uIG9mIGhlYXJ0IHRyYW5zcGxhbnQgcmVjaXBpZW50cyBmcm9tIDIwMDYtMjAxNSBiYXNlZCBvbiB0aGUgbmV3IFN0YXR1cyAxLTYgc3lzdGVtLgpgYGB7ciBzdGF0dXNfc2hpZnQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHMgPSAnYXNpcyd9CnRhbmdyYW06OnJtZCh0YW5ncmFtOjp0YW5ncmFtKGRhdGEgPSBzdGF0X2J5X2JlbmVmaXQsIHRocmVlX3N0YXR1c34gc2l4X3N0YXR1cykpCmBgYApDbGFzc2lmaWNhdGlvbiBvZiByZWNpcGllbnRzIGZyb20gMjAwNi0yMDE1IGJhc2VkIG9uIG5ldyBTdGF0dXMgMS02IHN5c3RlbS4gIFRoZSBtYWpvcml0eSAoIGByIGNvbW1hXzIoMTAwKmZpbHRlcihzdGF0dXNfc3dpdGNoLCBzaXhfc3RhdHVzID09MykkIlN0YXR1cyAxQSIvdG90XzFhcylgJSkgb2YgU3RhdHVzIDFBIHJlY2lwaWVudHMgd2VyZSBjb2RlZCBhcyBTdGF0dXMgMy4gQSBzdWJzdGFudGlhbCBwb3J0aW9uIChgciBjb21tYV8yKDEwMCpmaWx0ZXIoc3RhdHVzX3N3aXRjaCwgc2l4X3N0YXR1cyA9PTQpJCJTdGF0dXMgMUEiL3RvdF8xYXMpYCUpIG9mIFN0YXR1cyAxQSBjYW5kaWRhdGVzIHdvdWxkIGhhdmUgYmVlbiBkb3duZ3JhZGVkIHRvIFN0YXR1cyA0IGJlY2F1c2Ugb2YgdmlvbGF0aW9uIG9mIHRoZSBjYXJkaW9nZW5pYyBzaG9jayByZXF1aXJlbWVudC4gQSBzbWFsbCBudW1iZXIgb2YgcmVjaXBpZW50cyBgciBmaWx0ZXIoc3RhdHVzX3N3aXRjaCwgc2l4X3N0YXR1cyA9PTQpJCJTdGF0dXMgMiJgIHdlcmUgYXNzaWduZWQgYSBoaWdoZXIgc3RhdHVzIGJlY2F1c2Ugb2YgcmVzdHJpY3RpdmUgY2FyZGlvbXlvcGF0aHkKCiMjRmlndXJlIFM0OiBBc3NvY2lhdGlvbiBvZiBjZW50ZXIgdHJhbnNwbGFudCB2b2x1bWUgd2l0aCB3YWl0LWxpc3Qgc3Vydml2YWwsIHBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCwgYW5kIHN1cnZpdmFsIGJlbmVmaXQgZnJvbSBoZWFydCB0cmFuc3BsYW50YXRpb24uIApgYGB7ciBmaWd1cmVfUzRfc3VtbWFyeSwgbWVzc2FnZT1GQUxTRX0KdG9fcGxvdCA8LSBmaXZlX3llYXJfbWVhbnMgJT4lCiAgc2VsZWN0KG51bV90eCwgbWVhbl9maXZlX3llYXIsIG1lYW5fZml2ZV95ZWFyX3Bvc3QsIG1lYW5fZml2ZV95ZWFyX3dhaXQpICU+JQogIGdhdGhlcihrZXksIHZhbHVlLCAtbnVtX3R4KSAlPiUKICBtdXRhdGUoIGtleSA9IGNhc2Vfd2hlbigKICAgIGtleSA9PSAibWVhbl9maXZlX3llYXIiIH4gInN1cnZpdmFsIGJlbmVmaXQiLAogICAga2V5ID09ICJtZWFuX2ZpdmVfeWVhcl93YWl0IiB+ICJ3YWl0bGlzdCBzdXJ2aXZhbCIsCiAgICBrZXkgPT0gIm1lYW5fZml2ZV95ZWFyX3Bvc3QiIH4gInBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCIKICApCiAgKQoKZ2dwbG90KHRvX3Bsb3QsIGFlcyh4ID0gbnVtX3R4LCB5ID0gMTAwKnZhbHVlLCBjb2xvciA9IGtleSwgZ3JvdXAgPSBrZXkpKSArIAogIGdlb21fcG9pbnQoIHNpemUgPSAzKSArIGdlb21fc21vb3RoKCBtZXRob2QgPSAibG0iKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIGRpcmVjdGlvbiA9IC0xICkgKwogIGxhYnMoeSA9ICJGaXZlLXllYXIgZXN0aW1hdGUgKCUpIiwgIAogICAgICAgeCA9ICJOdW1iZXIgb2YgVHJhbnNwbGFudHMgcGVyZm9ybWVkIGR1cmluZyBzdHVkeSB0aW1lIHBlcmlvZCIsIAogICAgICAgY29sb3IgPSAiIikgKyAKICB5bGltKDAsIDEwMCkKCmdnc2F2ZSgiRmlnX1M0LnBkZiIpCmBgYApBY3Jvc3MgYWxsIGNlbnRlcnMsIHRyYW5zcGxhbnQgdm9sdW1lIHdhcyB3ZWFrbHkgYXNzb2NpYXRlZCB3aXRoIHBvc3QtdHJhbnNwbGFudCBzdXJ2aXZhbCAoYHIgdm9sdW1lX3Bvc3RfZGlmZmApLCBob3dldmVyIHdhcyBub3QgYXNzb2NpYXRlZCB3aXRoIGVpdGhlciBjYW5kaWRhdGUgdXJnZW5jeSAoYHIgdm9sdW1lX3dhaXRfZGlmZmApIG9yIHN1cnZpdmFsIGJlbmVmaXQgKGByIHZvbHVtZV9iZW5lZml0X2RpZmZgKSAoKipGaWd1cmUgUzQqKikuCgojIyBUYWJsZSBTNjogU2l4LXN0YXR1cyBgY294bWVgIHJlc3VsdHMKYGBge3Igc2l4X3N0YXR1c19kaXNwbGF5fQpwcmludChzaXhfc3RhdHVzLCBkaWdpdHMgPSAyKQpgYGAKIyMjIDk1JSBDb25maWRlbmNlIEludGVydmFscyBvZiBjb2VmZmljaWVudHMKYGBge3IgOTVfY2lfc2l4X3N0YXR1c30KI3dyaXRlX2Nzdih0YWJsZV9mZV9yZXN1bHRzKHNpeF9zdGF0dXMpLCAic2l4X3N0YXR1c19maXhlZC5jc3YiKQp0YWJsZV9mZV9yZXN1bHRzKHNpeF9zdGF0dXMpCmBgYAoKCmBgYHtyIHBsb3RfNl9zdGF0dXMsIG1lc3NhZ2UgPSBGQUxTRX0KdG9fcGxvdCA8LSBwbG90X3R4X2VmZmVjdHMoc2l4X3N0YXR1cykgJT4lIAogIG11dGF0ZShgUGF0aWVudCBTdGF0dXNgID0gZmFjdG9yKGNvdmFyaWF0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygidHgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInR4OnN0YXR1c18yIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHg6c3RhdHVzXzMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0eDpzdGF0dXNfNCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInR4OnN0YXR1c182IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidHhfcmlza3lfZG9uIiwiZXJhX3R4IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9ICBjKCJTdGF0dXMgMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgMyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgNCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGF0dXMgNiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIaWdoIHJpc2sgZG9ub3IgKFN0YXR1cyAxIHJlY2lwaWVudCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVmb3JlIDIwMTAgKFN0YXR1cyAxIHJlY2lwaWVudCkiKSkpCgpnZ3Bsb3QoZGF0YSA9IHRvX3Bsb3QgJT4lIAogICAgICAgICBmaWx0ZXIoIShjb3ZhcmlhdGUgJWluJSBjKCJ0eF9yaXNreV9kb24iLCJlcmFfdHgiKSkpLCAKICAgICAgIGFlcyh5ID0gYFBhdGllbnQgU3RhdHVzYCwgeCA9IGhheikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtaW4gPSBsb3dfY2ksIHhtYXggPSB1cF9jaSkpICArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMC43NSksIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41LCAwLjc1KSwgIAogICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkhhemFyZCBSYXRpbyBmb3IgZGVhdGggcmVsYXRpdmUgdG8gd2FpdGluZyIpICsKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKSArIAogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoKSwgCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuMSkpCgpzdGF0X2xpc3QgPC0gYygic3RhdHVzXzEiLCAic3RhdHVzXzIiLCAic3RhdHVzXzMiLCAic3RhdHVzXzQiLCAic3RhdHVzXzYiKQoKdHhfZXN0aW1hdGVzIDwtIHRpYmJsZShzdGF0dXMgPSBzdGF0X2xpc3QpICU+JQogIG11dGF0ZSgKICAgIGhhemFyZCA9ICIiLAogICAgbG93X2NpID0gIiIsIAogICAgdXBfY2kgPSAiIgogICkKCmkgPC0gMQpmb3IgKHMgaW4gc3RhdF9saXN0KSB7CiAgCiAgaWYgKHMgPT0gInN0YXR1c18xIil7CiAgICBpbnQgPC0gInR4IgogIH0KICBlbHNlewogICAgaW50IDwtIHBhc3RlMCgidHg6IiwgcykKICB9CiAgCiAgdHhfZXN0aW1hdGVzJGhhemFyZFtpXSA8LWNvbW1hXzIoZmlsdGVyKHRvX3Bsb3QsIGNvdmFyaWF0ZSA9PSBpbnQpJGhheikKICAKICB0eF9lc3RpbWF0ZXMkbG93X2NpW2ldIDwtY29tbWFfMihmaWx0ZXIodG9fcGxvdCwgY292YXJpYXRlID09IGludCkkbG93X2NpKQogIAogIHR4X2VzdGltYXRlcyR1cF9jaVtpXSA8LWNvbW1hXzIoZmlsdGVyKHRvX3Bsb3QsIGNvdmFyaWF0ZSA9PSBpbnQpJHVwX2NpKQogIAogIGkgPC0gaSArIDEKfQoKZ2dzYXZlKCJIUl90cmFuc3BsYW50X3NpeF9zdGF0dXMucGRmIikKYGBgCkhhemFyZCByYXRpb3Mgb2YgdHJhbnNwbGFudGF0aW9uIGJ5IDYtU3RhdHVzIEp1c3RpZmljYXRpb24gYXQgdHJhbnNwbGFudGF0aW9uIGFzIGVzdGltYXRlZCBieSBtaXhlZC1lZmZlY3RzIG1vZGVsLCBhZGp1c3RlZCBmb3IgZG9ub3IgcmlzaywgaXNjaGVtaWMgdGltZSwgYW5kIHllYXIgb2YgdHJhbnNwbGFudCAoc2VlIHN1cHBsZW1lbnQgZm9yIGZ1bGwgbW9kZWwgcmVzdWx0cykuCgpIYXphcmQgcmF0aW9zIG9mIHRyYW5zcGxhbnRhdGlvbiBjb25kaXRpb25hbCBTdGF0dXMgYXQgdHJhbnNwbGFudGF0aW9uIGFzIGVzdGltYXRlZCBieSBtaXhlZC1lZmZlY3RzIG1vZGVsIChzZWUgc3VwcGxlbWVudCBmb3IgZnVsbCBtb2RlbCByZXN1bHRzKS4gU3RhdHVzIDEgY2FuZGlkYXRlcyBoYWQgaGF6YXJkIHJhdGlvIG9mIHRyYW5zcGxhbnQgb2YgYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfMSIpJGhhemFyZGAgKDk1JSBDSSBgciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18xIikkbG93X2NpYC1gciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18xIikkdXBfY2lgKS4gQ29tcGFyZWQgdG8gdGhpcyBncm91cCwgU3RhdHVzIDItNiBjYW5kaWRhdGVzIGhhZCBzaWduaWZpY2FudGx5IGxvd2VyIGJlbmVmaXQgZnJvbSBoZWFydCB0cmFuc3BsYW5hdGlvbi4gCgpTdGF0dXMgMiBoYWQgYSBoYXphcmQgcmF0aW8gb2YgYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfMiIpJGhhemFyZGAgKDk1JSBDSSBgciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18yIikkbG93X2NpYC1gciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18yIikkdXBfY2lgKSwgU3RhdHVzIDMgYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfMyIpJGhhemFyZGAgKDk1JSBDSSBgciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18zIikkbG93X2NpYC1gciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c18zIikkdXBfY2lgKSwgU3RhdHVzIDQgYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfNCIpJGhhemFyZGAgKDk1JSBDSSBgciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c180IikkbG93X2NpYC1gciBmaWx0ZXIodHhfZXN0aW1hdGVzLCBzdGF0dXMgPT0gInN0YXR1c180IikkdXBfY2lgKSwgYW5kIFN0YXR1cyA2IGByIGZpbHRlcih0eF9lc3RpbWF0ZXMsIHN0YXR1cyA9PSAic3RhdHVzXzYiKSRoYXphcmRgICg5NSUgQ0kgYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfNiIpJGxvd19jaWAtYHIgZmlsdGVyKHR4X2VzdGltYXRlcywgc3RhdHVzID09ICJzdGF0dXNfNiIpJHVwX2NpYCkKCgojIFNlbnNpdGl2aXR5IGFuYWx5c2VzCgojIyBGaXhlZCBlZmZlY3RzIHNlbnNpdGl2aXR5IGFuYWx5c2lzCgpIZXJlIHdlIGZpdCB0aGUgbW9kZWwKCiRoKHQpID0gaF8wKHQpZXhwKGNlbnRlciArIHN0YXR1cyArIHR4KihjZW50ZXIgKyBzdGF0dXMgKyBkb25yaXNrICsgdHhZZWFyKSQKCmBgYHtyIGZpeGVkX2VmZmVjdHNfbW9kZWwsIGV2YWwgPSBGQUxTRX0KCm51bV90eF9ieV9jZW50ZXIgPC0gdG9fbW9kZWwgJT4lCiAgZmlsdGVyKGRlYWQgPT0xKSAlPiUKICBncm91cF9ieShjZW50ZXIpICU+JQogIGNvdW50KCkKCiNjZW50ZXIgNjAyIGlzIGNsb3NlIHRvIHRoZSAibWVhbiIgY2VudGVyCmZvcl9mZSA8LSB0b19tb2RlbCAlPiUKICBsZWZ0X2pvaW4obnVtX3R4X2J5X2NlbnRlciwgYnkgPSAiY2VudGVyIikgJT4lCiAgZmlsdGVyKG4+MjApICU+JQogIG11dGF0ZSh0aHJlZV9zdGF0dXMgPSBmYWN0b3IodGhyZWVfc3RhdHVzKSwKICAgICAgICAgY2VudGVyID0gZmFjdG9yKGNlbnRlciksCiAgICAgICAgIGNlbnRlciA9IHJlbGV2ZWwoY2VudGVyLCByZWYgPSAiNjAyIikpCiAgCmZ1bGxfZmUgPC0gIlN1cnYodF8xLCB0XzIsIGRlYWQpIH4gdHgqKHRocmVlX3N0YXR1cyArIGNlbnRlcikgKyB0eF9yaXNreV9kb24gKyBlcmFfdHgiCgpmdWxsX2ZlX21vZGVsIDwtIGNveHBoKGFzLmZvcm11bGEoZnVsbF9mZSksIGZvcl9mZSkKCmNlbnRlcnNfZXhsY3VkZWQgPC0gIGxlbmd0aCh1bmlxdWUodG9fbW9kZWwkY2VudGVyKSkgLSBsZW5ndGgobGV2ZWxzKGZvcl9mZSRjZW50ZXIpKQpgYGAKClRoaXMgbW9kZWwgdHJlYXRzIGNlbnRlciBhcyBhICpmaXhlZCogZWZmZWN0LiBUbyBnZXQgdGhpcyBtb2RlbCB0byBjb252ZXJnZSwgd2UgZXhjbHVkZWQgYHIgY2VudGVyc19leGxjdWRlZGAgY2VudGVycyB3aXRoIGxlc3MgdGhhbiAyMCBkZWF0aHMgKGJlZm9yZSBvciBhZnRlciB0cmFuc3BsYW50KQoKYGBge3IgdGFibGVfb3V0X2ZlX21vZGVsLCBpbmNsdWRlID0gRkFMU0V9CmZlX3RhYmxlX291dCA8LSBmdW5jdGlvbihtb2RlbCl7CgogIGNvdmFyaWF0ZXMgPC0gbmFtZXMobW9kZWwkY29lZmZpY2llbnRzKQogIAogIHN1bV9mZV9tb2RlbCA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMKICAKICBiZXRhcyA8LSB1bm5hbWUoc3VtX2ZlX21vZGVsWywxXSkKICBzZSA8LSB1bm5hbWUoc3VtX2ZlX21vZGVsWywzXSkKICAKICBjb3ZhcmlhdGVzCiB0aWJibGUoY292YXJpYXRlID0gY292YXJpYXRlcywKICAgICAgICBgbG9nIGhhemFyZCByYXRpb2AgPSBiZXRhcywKICAgICAgICBzZSA9IHNlKSAlPiUKICAgIG11dGF0ZShsb3dfY2kgPSBgbG9nIGhhemFyZCByYXRpb2AgLSAxLjk2KnNlLAogICAgICAgICAgIHVwX2NpID0gYGxvZyBoYXphcmQgcmF0aW9gICsgMS45NipzZSkgJT4lCiAgIHNlbGVjdCgtc2UpCiAgCn0KCgp3cml0ZS5jc3YoZmVfdGFibGVfb3V0KGZ1bGxfZmVfbW9kZWwpLCAiY2VudGVyX2ZlX21vZGVsLmNzdiIpCmBgYAoKYGBge3IgcHJpbnRfZmVfbW9kZWx9CnByaW50KGZ1bGxfZmVfbW9kZWwsIGRpZ2l0cyA9IDIpCmBgYAoKYGBge3IgdHJhbnNwbGFudF9maXhlZF9lZmZlY3RzX2J5X2NlbnRlcn0Kc3VtX2ZlX21vZGVsIDwtIHN1bW1hcnkoZnVsbF9mZV9tb2RlbCkkY29lZmZpY2llbnRzCgp0eF8xYSA8LSBzdW1fZmVfbW9kZWxbMSwxXQogIApmZV9jb2VmIDwtIHRpYmJsZShuYW1lID0gbmFtZXMoZnVsbF9mZV9tb2RlbCRjb2VmZmljaWVudHMpLCAKICAgICAgICAgICAgICAgICAgYmV0YSA9IHVubmFtZShzdW1fZmVfbW9kZWxbLDFdKSkgJT4lCiAgZmlsdGVyKGdyZXBsKCAiY2VudGVyIixuYW1lKT09IFRSVUUpICU+JQogIG11dGF0ZSh0eCA9IGlmZWxzZShncmVwbCggInR4OiIsbmFtZSksICJ0cmFuc3BsYW50IiwgIndhaXRsaXN0IiksCiAgICAgICAgIGNlbnRlciA9IG51bWV4dHJhY3QobmFtZSkpICU+JQogIHNlbGVjdCgtbmFtZSkgJT4lCiAgc3ByZWFkKHR4LCBiZXRhKQogIAp2Y292X2Z1bGxfZmUgPC0gdmNvdihmdWxsX2ZlX21vZGVsKQoKdHhfd2FpdF9jb3YgPC0gdmVjdG9yKCJkb3VibGUiLCBsZW5ndGggPSBsZW5ndGgodW5pcXVlKGZvcl9mZSRjZW50ZXIpKSkKY2VudGVyX2lkcyA8LSB2ZWN0b3IoImRvdWJsZSIsIGxlbmd0aCA9IGxlbmd0aCh1bmlxdWUoZm9yX2ZlJGNlbnRlcikpKQp3YWl0X3ZhcmlhbmNlIDwtIHZlY3RvcigiZG91YmxlIiwgbGVuZ3RoID0gbGVuZ3RoKHVuaXF1ZShmb3JfZmUkY2VudGVyKSkpCnR4X3ZhcmlhbmNlIDwtIHZlY3RvcigiZG91YmxlIiwgbGVuZ3RoID0gbGVuZ3RoKHVuaXF1ZShmb3JfZmUkY2VudGVyKSkpCmkgPC0gMQpqIDwtIDEKZm9yIChuIGluIG5hbWVzKHZjb3ZfZnVsbF9mZVssMV0pKXsKICBpZiAoZ3JlcGwoImNlbnRlciIsIG4pID09IFRSVUUgJiBncmVwbCgidHgiLCBuKSA9PSBGQUxTRSl7CiAgICB0eF9lZmZlY3QgPC0gcGFzdGUwKCJ0eDoiLG4pCiAgICB0eF93YWl0X2NvdltbaV1dIDwtIHZjb3ZfZnVsbF9mZVtbdHhfZWZmZWN0LG5dXQogICAgCiAgICB3YWl0X3ZhcmlhbmNlW1tpXV0gPC0gdmNvdl9mdWxsX2ZlW1tuLG5dXQogICAgY2VudGVyX2lkc1tbaV1dIDwtIG51bWV4dHJhY3QobikKICAgIGkgPC0gaSArIDEKICB9CiAgaWYgKGdyZXBsKCJ0eDpjZW50ZXIiLCBuKSA9PSBUUlVFKXsKICAgIHR4X3ZhcmlhbmNlW1tqXV0gPC0gdmNvdl9mdWxsX2ZlW1tuLCBuXV0KICAgIGogPC0gaiArIDEKICB9Cn0KCnR4X3dhaXRfY292IDwtIHRpYmJsZShjZW50ZXIgPSBjZW50ZXJfaWRzLCAKICAgICAgICAgICAgICAgICAgICAgIHdhaXRfdmFyaWFuY2UgPSB3YWl0X3ZhcmlhbmNlLCAKICAgICAgICAgICAgICAgICAgICAgIHR4X3ZhcmlhbmNlID0gdHhfdmFyaWFuY2UsIAogICAgICAgICAgICAgICAgICAgICAgY292YXJpYW5jZSA9IHR4X3dhaXRfY292KQoKCmZlX2NvZWYgPC0gZmVfY29lZiAlPiUKICBsZWZ0X2pvaW4odHhfd2FpdF9jb3YpICU+JQogIG11dGF0ZSh0eF9iZW5lZml0ID0gIHRyYW5zcGxhbnQgLSB3YWl0bGlzdCkgJT4lCiAgYXJyYW5nZSgtdHhfYmVuZWZpdCkgJT4lCiAgbXV0YXRlKGlkID0gcm93X251bWJlcigpKQpgYGAKCgojIyMgSGlzdG9ncmFtIG9mIGNlbnRlciByZWxhdGl2ZSBzdXJ2aXZhbCBiZW5lZml0cwpgYGB7ciBoaXN0b2dyYW1fZmUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ2dwbG90KGZlX2NvZWYsIGFlcyh4ID0gdHhfYmVuZWZpdCkpICsgZ2VvbV9oaXN0b2dyYW0oYnJlYWtzID0gc2VxKC0zLCAyLCAwLjI1KSkKICBsYWJzKHggPSAiY2VudGVyIGVmZmVjdCBvbiBiZW5lZml0IG9mIHRyYW5zcGxhbnRcbihsb2cgaGF6YXJkIHJhdGlvIG9mIHRyYW5zcGxhbnQgKFN0YXR1cyAxQSkiLCAKICAgICAgIHkgPSAibnVtYmVyIG9mIGNlbnRlcnMiKSArCiAgdGhlbWVfZmV3KCkKCmdnc2F2ZSgiZUZpZ3VyZTYucGRmIikKCnNfd19ub3JtX3Rlc3QgPC0gY29tbWFfMihzaGFwaXJvLnRlc3QoZmVfY29lZiR0eF9iZW5lZml0KVtbMl1dKQpgYGAKRGlzdHJpYnV0aW9uIG9mIGNlbnRlci1zcGVjaWZpYyBzdXJ2aXZhbCBiZW5lZml0cyBmb3IgYSBTdGF0dXMgMUEgcmVjaXBpZW50LCBjYWxjdWxhdGVkIGJ5IHN1YnRyYWN0aW5nIHRoZSBsb2cgaGF6YXJkIG9mIHdhaXRsaXN0IGZyb20gdGhlIHRoZSBsb2cgaGF6YXJkIG9mIHRyYW5zcGxhbnQgYXQgdGhlIGNlbnRlci4gVGhlIHNoYXBpcm8td2lsayB0ZXN0IGZvciBub24tbm9ybWFsaXR5IHdhcyBub3Qgc2lnbmlmaWNhbnQgKHAgPSBgciBzX3dfbm9ybV90ZXN0YCkuIFRoZSB2YXJpYW5jZSBvZiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiB0cmFuc3BsYW50IHdhcyBgciBjb21tYSh2YXIoZmVfY29lZiR0eF9iZW5lZml0KSlgIG9uIGxvZyBoYXphcmQgcmF0aW8gc2NhbGUsIGByIGNvbW1hXzIoMTAwKih0aHJlZV9zdGF0dXNfdmFyLXZhcihmZV9jb2VmJHR4X2JlbmVmaXQpKS90aHJlZV9zdGF0dXNfdmFyKWAlIGxvd2VyIHRoYW4gdGhlIHRocmVlLXN0YXR1cyBtb2RlbC4KCgokYmVuZWZpdCA9IFxiZXRhX3t0eCwgaX0gLSBcYmV0YV97d2FpdCwgaX0kCgoKIyMgUmVsYXRpb25zaGlwIGJldHdlZW4gZml4ZWQtZWZmZWN0IGFuZCByYW5kb20tZWZmZWN0IGNlbnRlciBlc3RpbWF0ZXMgb2Ygc3Vydml2YWwgYmVuZWZpdCBmcm9tIGhlYXJ0IHRyYW5zcGxhbnRhdGlvbi4KYGBge3IgZmVfdnNfcmVfcGxvdCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9Cgpmb3Jfc3BlYXIgPC0gY2VudGVyX3JlICU+JQogIGZpbHRlcihjZW50ZXIgJWluJSBmZV9jb2VmJGNlbnRlcikgJT4lCiAgbGVmdF9qb2luKGZlX2NvZWYgJT4lIHNlbGVjdChjZW50ZXIsIHR4X2JlbmVmaXQpKQoKc3BlYXJtYW5fY29yIDwtIGNvcihmb3Jfc3BlYXIkYmVuZWZpdCwgZm9yX3NwZWFyJHR4X2JlbmVmaXQsbWV0aG9kID0gInNwZWFybWFuIikKCmdncGxvdChmb3Jfc3BlYXIsIGFlcyh4ID0gYmVuZWZpdCwgeSA9IHR4X2JlbmVmaXQpKSArIGdlb21fcG9pbnQoKSArCiAgbGFicyggeCA9ICJiZW5lZml0IG9mIHRyYW5zcGxhbnQgKFJFIGVzdGltYXRlKSBsb2cgaGF6YXJkIiwgCiAgICAgICAgeSA9ICJiZW5lZml0IG9mIHRyYW5zcGxhbnQgKEZFIGVzdGltYXRlKSBsb2cgaGF6YXJkIikKCmdnc2F2ZSgiZUZpZzcucGRmIikKYGBgClNjYXR0ZXIgcGxvdCBvZiBjZW50ZXIgZml4ZWQtZWZmZWN0ICh5LWF4aXMpIGFuZCByYW5kb20tZWZmZWN0ICh4LWF4aXMpIGVzdGltYXRlcyBvZiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiBoZWFydCB0cmFuc3BsYW50YXRpb24gKG9uIGxvZyBoYXphcmQgc2NhbGUpLiBBIHNwZWFybWFuIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHR3byB3YXMgYHIgc3BlYXJtYW5fY29yYAoKCgojIyMgQXNzb2NpYXRpb24gb2YgY2VudGVyIHdhaXRsaXN0IHJpc2sgd2l0aCBzdXJ2aXZhbCBiZW5lZml0IGZyb20gdHJhbnNwbGFudGF0aW9uIApgYGB7ciBlRmlnXzgsICB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KCmdncGxvdChmZV9jb2VmLCBhZXMoeCA9IHdhaXRsaXN0LCB5ID0gdHhfYmVuZWZpdCkpICsgZ2VvbV9wb2ludChzaXplID0gMi41LCBhbHBoYSA9IDAuOSkgKwogIGxhYnMoeCA9ICJXYWl0bGlzdCByZWxhdGl2ZSByaXNrIChsb2cgaGF6YXJkKSIsIAogICAgICAgeSA9ICJSZWxhdGl2ZSBiZW5lZml0IG9mIHRyYW5zcGxhbnQgKGxvZyBoYXphcmQpIikgKwogIGdlb21fbGluZShhZXMobGluZXR5cGUgPSAiTWVhbiBDZW50ZXIiKSwgCiAgICAgICAgICAgIHkgPSAwLCBjb2xvciA9ICJibGFjayIpICsgCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9ICJkYXNoZWQiKSAKCgpzbG9wZV9mZSA8LSBsbSh0eF9iZW5lZml0IH4gd2FpdGxpc3QsIGRhdGEgPSBmZV9jb2VmKQoKc2xvcGVfcGN0X2ZlIDwtIGNvbW1hXzIoc2xvcGVfZmUkY29lZmZpY2llbnRzW1syXV0pCgpjaV9zbG9wZV9mZV93YWl0X2xvdyA8LSBjb21tYV8yKDEwKi1jb25maW50KHNsb3BlX2ZlLCAnd2FpdGxpc3QnLCBsZXZlbD0wLjk1KVsxLDFdKQoKY2lfc2xvcGVfZmVfd2FpdF91cCA8LSBjb21tYV8yKDEwKi1jb25maW50KHNsb3BlX2ZlLCAnd2FpdGxpc3QnLCBsZXZlbD0wLjk1KVsxLDJdKQoKZ2dzYXZlKCJlRmlndXJlOC5wZGYiKQpgYGAKVGhlIGFzc29jaWF0aW9uIGJldHdlZW4gZXN0aW1hdGVkIGxvZyBoYXphcmQgb2YgZGVhdGggb24gd2FpdGxpc3QgYXQgYSBnaXZlbiBjZW50ZXIgKHgtYXhpcykgYW5kIGxvZyBoYXphcmQgc3Vydml2YWwgYmVuZWZpdCAoeS1heGlzKS4gQSBsaW5lYXIgYXNzb2NpYXRpb24gaXMgb2JzZXJ2ZWQsIGZvciBldmVyeSBvbmUgdW5pdCBpbmNyZWFzZSBpbiB0aGUgbG9nIGhhemFyZCBvZiB3YWl0bGlzdCByaXNrIHRoZSBsb2cgaGF6YXJkIG9mIHRyYW5zcGxhbnQgZGVjcmVhc2VkIGByIHNsb3BlX3BjdF9mZWAgKDk1JSBDSSBgciBjaV9zbG9wZV9mZV93YWl0X2xvd2AgLSBgciBjaV9zbG9wZV9mZV93YWl0X3VwYCkuCgojIyBBbHRlcm5hdGl2ZSBNRSBtb2RlbHMKYGBge3IgZGF0YV9pbl9yZXZpc2lvbiwgZXZhbCA9IEZBTFNFfQp0b19tb2RlbCA8LSByZWFkLmNzdigiY2xlYW5fdGltZV9zZXJpZXNfcmV2aXNlMjAwNl8yMDE1LmNzdiIpICU+JQogIG11dGF0ZSgKICAJaXNjaGVtaWEgPSBjYXNlX3doZW4oCgkJCVJFQ19IUl9JU0NILzYwIDwgMiB+IDEsCgkJCVJFQ19IUl9JU0NILzYwID49IDIgJiBSRUNfSFJfSVNDSC82MCA8IDQgfiAyLAoJCQlSRUNfSFJfSVNDSC82MCA+PTQgJiBSRUNfSFJfSVNDSC82MCA8IDYgfiAzLAoJCQlSRUNfSFJfSVNDSC82MCA+PSA2ICYgUkVDX0hSX0lTQ0gvNjAgPCA4IH40LAoJCQlUUlVFIH4gNQogIAkpLApkb25fYWdlID0gZmFjdG9yKGNhc2Vfd2hlbigKCQkJRE9OX0FHRSA+PTQwICYgRE9OX0FHRSA8NTAgfiAiMzAtNTAiLAoJCQlET05fQUdFID49IDUwIH4gIj4gNTAiLAoJCQlUUlVFIH4gIjwgMzAiCgkJKSksCmRvbl9yZW5hbF9mdW5jdGlvbiA9IAoJCWNhc2Vfd2hlbigKCQkJKERPTl9CVU4vRE9OX0NSRUFUKSA+IDMwIH4gMSwKCQkJVFJVRSB+IDAKCQkpLApyYWNlX21pc21hdGNoID0gCgkJY2FzZV93aGVuKAoJCQlibGFjayAhPSBibGFja19kb24gfiAxLAoJCQlUUlVFIH4gMAoJCSkKCSkKYGBgCgoKCiMjIyBNRSBzZW5zaXRpdml0eSBhbmFseXNlcwoKCjEuIGJldHRlcl9kb25vcl95ZWFyIDwtICJTdXJ2KHRfMSwgdF8yLCBkZWFkKSB+IHR4KihzdGF0XzIgKyBzdGF0XzFiICsgZmFjdG9yKGxpc3RfeWVhcikpICsgZG9uX3JlbmFsX2Z1bmN0aW9uICsgZG9uX2FnZSArIHJhY2VfbWlzbWF0Y2ggKyBpc2NoZW1pYSIKCgoyLiBzaXgtc3RhdHVzLCBkb25vciBxdWFsaXR5IGFuZCB0cmFuc3BsYW50IHllYXIKYmV0dGVyX2Rvbm9yX3llYXJfY2FuZGlkYXRlIDwtICJTdXJ2KHRfMSwgdF8yLCBkZWFkKSB+IHR4KihzdGF0XzIgKyBzdGF0XzFiICsgZmFjdG9yKGxpc3RfeWVhcikgKyBhZ2UgKyBmZW1hbGUgKyBibWlfbG93ICsgYm1pX2hpZ2ggKyBzaW1wbGVfZGlhZyArIGNyb3NzX21hdGNoICtibG9vZF90eXBlKSArIGRvbl9yZW5hbF9mdW5jdGlvbiArIGRvbl9hZ2UgKyByYWNlX21pc21hdGNoICsgaXNjaGVtaWEiCgoKMy4gdGhyZWUgc3RhdHVzLCByZWdpb24gJiBMVkFECnJlZ2lvbl9sdmFkIDwtICJTdXJ2KHRfMSwgdF8yLCBkZWFkKSB+IHR4KihzdGF0XzIgKyBzdGF0XzFiICsgZmFjdG9yKFJFR0lPTikgKyBjZl9sdmFkKSArIHR4X3Jpc2t5X2RvbiArIGVyYV90eCIKCmBgYHtyIGZvcm11bGFzX21vZGVsc19zZW5zfQojdGhyZWUtc3RhdHVzLCBkb25vciBxdWFsaXR5LCBhbmQgdHJhbnNwbGFudCB5ZWFyCmJldHRlcl9kb25vcl95ZWFyIDwtICJTdXJ2KHRfMSwgdF8yLCBkZWFkKSB+IHR4KihzdGF0XzIgKyBzdGF0XzFiICsgZmFjdG9yKGxpc3RfeWVhcikpICsgZG9uX3JlbmFsX2Z1bmN0aW9uICsgZG9uX2FnZSArIHJhY2VfbWlzbWF0Y2ggKyBpc2NoZW1pYSIKCgojc2l4LXN0YXR1cywgZG9ub3IgcXVhbGl0eSBhbmQgdHJhbnNwbGFudCB5ZWFyCmJldHRlcl9kb25vcl95ZWFyX2NhbmRpZGF0ZSA8LSAiU3Vydih0XzEsIHRfMiwgZGVhZCkgfiB0eCooc3RhdF8yICsgc3RhdF8xYiArIGZhY3RvcihsaXN0X3llYXIpICsgYWdlICsgZmVtYWxlICsgYm1pX2xvdyArIGJtaV9oaWdoICsgc2ltcGxlX2RpYWcgKyBjcm9zc19tYXRjaCArYmxvb2RfdHlwZSkgKyBkb25fcmVuYWxfZnVuY3Rpb24gKyBkb25fYWdlICsgcmFjZV9taXNtYXRjaCArIGlzY2hlbWlhIgoKCiN0aHJlZSBzdGF0dXMsIHJlZ2lvbiAmIExWQUQKcmVnaW9uX2x2YWQgPC0gIlN1cnYodF8xLCB0XzIsIGRlYWQpIH4gdHgqKHN0YXRfMiArIHN0YXRfMWIgKyBmYWN0b3IoUkVHSU9OKSArIGNmX2x2YWQpICsgdHhfcmlza3lfZG9uICsgZXJhX3R4IgpgYGAKCgoKYGBge3IgcnVuX2ZlX2NveF9tb2RlbHNfc2VucywgaW5jbHVkZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9CmZvcm11bGFzX2FsdCA8LSBjKGJldHRlcl9kb25vcl95ZWFyLGJldHRlcl9kb25vcl95ZWFyX2NhbmRpZGF0ZSwgcmVnaW9uX2x2YWQpCgpmZV9tb2RlbHNfYWx0IDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGgoZm9ybXVsYXNfYWx0KSkKCmZvciAoaSBpbiBzZXFfYWxvbmcoZm9ybXVsYXNfYWx0KSkgewogIGNveHBoX2ZlPC0gY294cGgoYXMuZm9ybXVsYShmb3JtdWxhc19hbHRbW2ldXSksIHRvX21vZGVsKQogIHByaW50KGZvcm11bGFzX2FsdFtbaV1dKQogIHByaW50KGNveHBoX2ZlKQogIGZlX21vZGVsc19hbHRbW2ldXSA8LSBjb3hwaF9mZQp9CmBgYAoKCmBgYHtyIGZpdF9tZV9tb2RlbF9zZW5zLCBldmFsPUZBTFNFfQptZV9tb2RlbHNfYWx0IDwtICB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoKGZvcm11bGFzX2FsdCkpCgpmb3IgKGkgaW4gc2VxX2Fsb25nKGZvcm11bGFzX2FsdCkpIHsKICBmX2NveG1lIDwtIGFzLmZvcm11bGEocGFzdGUoZm9ybXVsYXNfYWx0W1tpXV0sICIgKyAoMSsgdHh8Y2VudGVyKSIpKQogIHN0YXJ0X3RpbWUgPC0gU3lzLnRpbWUoKQogIGZpdCA8LSBjb3htZShmX2NveG1lLCBkYXRhID0gdG9fbW9kZWwpCiAgbWVfbW9kZWxzX2FsdFtbaV1dIDwtIGZpdAogIGVuZF90aW1lIDwtIFN5cy50aW1lKCkKICBkaWZmX3RpbWUgPC0gZW5kX3RpbWUgLSBzdGFydF90aW1lCiAgcHJpbnQoZl9jb3htZSkKICBwcmludChkaWZmX3RpbWUpCn0KCnNhdmUuaW1hZ2UoImVuZF9yZXN1bHRzX3dpdGhfYWx0cy5SRGF0YSIpCmBgYAoKCgojIyBFeHBhbmRlZCBkb25vciBmYWN0b3JzCmBgYHtyIGVUYWJsZTh9CnByaW50KG1lX21vZGVsc19hbHRbWzFdXSkKCndyaXRlX2Nzdih0YWJsZV9mZV9yZXN1bHRzKG1lX21vZGVsc19hbHRbWzFdXSksICJleHBhbmRlZF9kb25vcl90aW1lLmNzdiIpCgp0aHJlZV9zdGF0X2Rvbl95ZWFyIDwtIHZhcmlhbmNlX3N1cnZpdmFsX2JlbmVmaXQobWVfbW9kZWxzX2FsdFtbMV1dKQpgYGAKVGhlIHZhcmlhbmNlIG9mIHRoZSBzdXJ2aXZhbCBiZW5lZml0IG9mIHRyYW5zcGxhbnQgd2FzIGByIGNvbW1hKHRocmVlX3N0YXRfZG9uX3llYXIpYCBvbiBsb2cgaGF6YXJkIHJhdGlvIHNjYWxlLCBgciBjb21tYV8yKDEwMCoodGhyZWVfc3RhdHVzX3Zhci10aHJlZV9zdGF0X2Rvbl95ZWFyKS90aHJlZV9zdGF0dXNfdmFyKWAlIGxvd2VyIHRoYW4gdGhlIHRocmVlLXN0YXR1cyBtb2RlbC4KCgojIyBFeHBhbmRlZCBkb25vciBmYWN0b3JzIGFuZCBjYW5kaWRhdGUgdmFyaWFibGVzCmBgYHtyIGV0YWJsZV85fQoKcHJpbnQobWVfbW9kZWxzX2FsdFtbMl1dLCBkaWdpdHMgPSAyKQoKCndyaXRlX2Nzdih0YWJsZV9mZV9yZXN1bHRzKG1lX21vZGVsc19hbHRbWzJdXSksICJleHBhbmRlZF9kb25vcl90aW1lX2Nhbl9mYWN0b3JzLmNzdiIpCgp0aHJlZV9zdGF0X2Rvbl95ZWFyX2NhbiA8LSB2YXJpYW5jZV9zdXJ2aXZhbF9iZW5lZml0KG1lX21vZGVsc19hbHRbWzJdXSkKYGBgClRoZSB2YXJpYW5jZSBvZiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiB0cmFuc3BsYW50IHdhcyBgciBjb21tYSh0aHJlZV9zdGF0X2Rvbl95ZWFyX2NhbilgIG9uIGxvZyBoYXphcmQgcmF0aW8gc2NhbGUsIGByIGNvbW1hXzIoMTAwKih0aHJlZV9zdGF0dXNfdmFyLXRocmVlX3N0YXRfZG9uX3llYXJfY2FuKS90aHJlZV9zdGF0dXNfdmFyKWAlIGxvd2VyIHRoYW4gdGhlIHRocmVlLXN0YXR1cyBtb2RlbC4KCiMjIEJUVCBMVkFEIGFuZCBVTk9TIFJlZ2lvbgpgYGB7cn0KcHJpbnQobWVfbW9kZWxzX2FsdFtbM11dKQoKd3JpdGVfY3N2KHRhYmxlX2ZlX3Jlc3VsdHMobWVfbW9kZWxzX2FsdFtbM11dKSwgImJ0dF9sdmFkX2FuZF9yZWdpb24uY3N2IikKCmJ0dF9sdmFkX3JlZ2lvbiA8LSB2YXJpYW5jZV9zdXJ2aXZhbF9iZW5lZml0KG1lX21vZGVsc19hbHRbWzNdXSkKYGBgClRoZSB2YXJpYW5jZSBvZiB0aGUgc3Vydml2YWwgYmVuZWZpdCBvZiB0cmFuc3BsYW50IGluIHRoZSBtb2RlbCBpbmNsdWRpbmcgVU5PUyByZWdpb24gYW5kIExWQUQgd2FzIGByIGNvbW1hKGJ0dF9sdmFkX3JlZ2lvbilgIG9uIGxvZyBoYXphcmQgcmF0aW8gc2NhbGUsIGByIGNvbW1hXzIoMTAwKih0aHJlZV9zdGF0dXNfdmFyLWJ0dF9sdmFkX3JlZ2lvbikvdGhyZWVfc3RhdHVzX3ZhcilgJSBsb3dlciB0aGFuIHRoZSB0aHJlZS1zdGF0dXMgbW9kZWwuCgoK